Jump to content

Controlling a web relay with XML


Recommended Posts

Hi all

I am interested to know if there's any suggested reading and/or viewing that can help me achieve the following.

I have a webrelay device on my network that controls a magnetic door lock. The device supports XML and HTTP GET requests. I have created a basic map of the property in filemaker and want to use a  button to toggle the control the relay (thus locking or unlocking the door) and return the device status'. Conditional formatting will indicate whether the lock is energized or not, with a separate field indicating whether the door is closed (inputstate). The XML (state.xml) file on the device is as follows...

<?xml version="1.0" encoding="utf-8" ?>
-<datavalues>
	<relaystate>1</relaystate>
	<inputstate>0</inputstate>
	<rebootstate>0</rebootstate>
	<totalreboots>0</totalreboots>
</datavalues>

The two values I am most interested in are <relaystate> (0 = off, 1 = on) and <inputstate> (0 = off, 1 = on). As I'm trying this on one lock system there is only one set of records in the FMP file (relaystate and inputstate).

Where I'm having issues is creating the XSLT file so FileMaker understands the XML file. I attempted the following using an example file from the FMP website but FMP does not like it and gives me an XML Parsing Error:

<?xml version=“1.0 encoding=“UTF-8”?>
<xsl:stylesheet xmlns:xsl=“http://www.w3.org/1999/XSL/Transform” version=“1.0”>
<!--
File: state.xslt

-->

	<xsl:template match=“/*”>
		<FMPXMLRESULT xmlns=“http://www.filemaker.com/fmpxmlresult”>
			<ERRORCODE>0</ERRORCODE>
			<PRODUCT BUILD=“” NAME=“” VERSION=“”/>
			<DATABASE DATEFORMAT=“M/d/yyyy” LAYOUT=“” NAME=“” RECORDS=“{count(/*/*)}” TIMEFORMAT=“h:mm:ss a/>
			<METADATA>
				<xsl:for-each select=“/*/*[position()=1]/*”>
					<FIELD>
						<xsl:attribute name=“relaystate”>1</xsl:attribute>
						<xsl:attribute name=“inputatestate”>0</xsl:attribute>
						<xsl:attribute name=“rebootstate”>0</xsl:attribute>
						<xsl:attribute name=“totalreboots”>0</xsl:attribute>
					</FIELD>
				</xsl:for-each>
			</METADATA>
			<RESULTSET>
				<xsl:attribute name=“FOUND”><xsl:value-of select=“count(child::*)”/></xsl:attribute>
				<xsl:for-each select=“child::*”>
					<ROW>
						<xsl:attribute name=“MODID”>0</xsl:attribute>
						<xsl:attribute name=“RECORDID”>0</xsl:attribute>
						<xsl:for-each select=“child::*”>
							<COL>
									<DATA>
										<xsl:value-of select=“.”/>
									</DATA>
							</COL>
						</xsl:for-each>
					</ROW>
			</RESULTSET>
		</FMPXMLRESULT>
	</xsl:template>
</xsl:stylesheet>

A push in the right direction would be appreciated.

Link to post
Share on other sites

Can you please export the layout as FMPXMLRESULT with one record for the layout that you would like to use as a template for the import?

I took the liberty: https://gist.github.com/TyrfingMjolnir/98bfc677669e91df1dc55d0f24d62747

Edited by ggt667
Link to post
Share on other sites
1 hour ago, madman411 said:

Where I'm having issues is creating the XSLT file so FileMaker understands the XML file.

Are you trying to import the XML file? If so, try the following XSLT:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/datavalues">
	<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
		<!-- FIELDS -->
		<METADATA>
			<FIELD NAME="RelayState" TYPE="NUMBER"/>
			<FIELD NAME="InputState" TYPE="NUMBER"/>
			<FIELD NAME="RebootState" TYPE="NUMBER"/>
			<FIELD NAME="TotalReboots" TYPE="NUMBER"/>
		</METADATA>
		<!-- DATA -->
		<RESULTSET>
			<ROW>
				<COL><DATA><xsl:value-of select="relaystate"/></DATA></COL>
				<COL><DATA><xsl:value-of select="inputstate"/></DATA></COL>
				<COL><DATA><xsl:value-of select="rebootstate"/></DATA></COL>
				<COL><DATA><xsl:value-of select="totalreboots"/></DATA></COL>
			</ROW>
		</RESULTSET>
	</FMPXMLRESULT>
</xsl:template>

</xsl:stylesheet>

 

This will create a single record with 4 fields that you can map to 4 (or less) corresponding fields in your Filemaker table.

Note that this will NOT work if your input file contains EXACTLY what you posted here. You will get a parsing error because there is text (a hyphen character) at the root level, which is not allowed in XML.

 

 

Link to post
Share on other sites
1 minute ago, comment said:

Note that this will NOT work if your input file contains EXACTLY what you posted here. You will get a parsing error because there is text (a hyphen character) at the root level, which is not allowed in XML.

Valid point; yet most likely copy / pasted from some sort of browser that can collapse closures.

Link to post
Share on other sites
52 minutes ago, ggt667 said:

Can you please export the layout as FMPXMLRESULT with one record for the layout that you would like to use as a template for the import?

Hi there

Is this what you're looking for?

 

<?xml version="1.0" encoding="UTF-8" ?>
<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult"><ERRORCODE>0</ERRORCODE>

<PRODUCT BUILD="09-05-2019" NAME="FileMaker" VERSION="ProAdvanced 18.0.3"/>
<DATABASE DATEFORMAT="M/d/yyyy" LAYOUT="" NAME="Doors.fmp12" RECORDS="1" TIMEFORMAT="h:mm:ss a"/>
  
<METADATA>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="DOOR" TYPE="TEXT"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="inputstate" TYPE="NUMBER"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="rebootstate" TYPE="NUMBER"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="relaystate" TYPE="NUMBER"/>
<FIELD EMPTYOK="YES" MAXREPEAT="1" NAME="totalreboots" TYPE="NUMBER"/>
</METADATA>
  
<RESULTSET FOUND="1">
<ROW MODID="21" RECORDID="1">
<COL>
<DATA>1</DATA>
</COL>
<COL>
<DATA>0</DATA>
</COL>
<COL>
<DATA>0</DATA>
</COL>
<COL>
<DATA>1</DATA>
</COL>
<COL>
<DATA>0</DATA>
</COL>
</ROW>
</RESULTSET>
</FMPXMLRESULT>

 

19 minutes ago, comment said:

Are you trying to import the XML file? If so, try the following XSLT:


<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/datavalues">
	<FMPXMLRESULT xmlns="http://www.filemaker.com/fmpxmlresult">
		<!-- FIELDS -->
		<METADATA>
			<FIELD NAME="RelayState" TYPE="NUMBER"/>
			<FIELD NAME="InputState" TYPE="NUMBER"/>
			<FIELD NAME="RebootState" TYPE="NUMBER"/>
			<FIELD NAME="TotalReboots" TYPE="NUMBER"/>
		</METADATA>
		<!-- DATA -->
		<RESULTSET>
			<ROW>
				<COL><DATA><xsl:value-of select="relaystate"/></DATA></COL>
				<COL><DATA><xsl:value-of select="inputstate"/></DATA></COL>
				<COL><DATA><xsl:value-of select="rebootstate"/></DATA></COL>
				<COL><DATA><xsl:value-of select="totalreboots"/></DATA></COL>
			</ROW>
		</RESULTSET>
	</FMPXMLRESULT>
</xsl:template>

</xsl:stylesheet>

 

This will create a single record with 4 fields that you can map to 4 (or less) corresponding fields in your Filemaker table.

Note that this will NOT work if your input file contains EXACTLY what you posted here. You will get a parsing error because there is text (a hyphen character) at the root level, which is not allowed in XML.

 

 

Thanks comment. The input file I copied directly from the manufacturers instructions. Will give this a go.

Link to post
Share on other sites

Yes, but I took the liberty and posted based on your input file on my gist in the link as described in my post above.

@comment and my example does the same if you only have 1 record, the one I posted will be able to separate records properly without adding metadata for each record.

There are benefits to using the command line tool `tidy`, Xmplify.app or similar in Mac OS X while developing, then again when you are done making it work there are no benefits to line breaks in XML or XSLT. Rather on the contrary different systems may interpret different kinds of separators for line breaks amongst others.

As pr example `tidy -i -xml -wrap 0 /tmp/file.xml`

Edited by ggt667
  • Like 1
Link to post
Share on other sites

@ggt667 and @comment - thank you both! Now my FMP application and read the XML file and import from state.xml :)

Now my final task of using FMP to update the XML. 

I have created a script using Insert from URL. The network device supports control via URL commands, for example, typing

http://10.0.1.90/state.xml?relayState=0

into the address bar will set the relaystate to 0, etc.

The script uses a Case () function to determine if "1" or "0" should be sent in the URL but I'm currently getting a progress bar saying "URL data transfer" that stays on the screen for a long time without doing anything. I've attempted using

 httpget://10.0.1.90/state.xml?relayState=0

and 

http://10.0.1.90/state.xml?relayState=0

Obviously I'm doing something wrong with sending the URL.

Link to post
Share on other sites

Currently just using a hidden web viewer to send commands as I think this is the only way to send a URL.

Link to post
Share on other sites

I am afraid this is rather confusing (and also should be in a separate thread, IMHO). 

Are you able to change the state using your browser? If so, does the same URL work in a web-viewer? And does the same URL work in Insert from URL. (without using a calculation to generate the URL)?

 

Link to post
Share on other sites
Posted (edited)
17 hours ago, madman411 said:

The script uses a Case () function to determine if "1" or "0" should be sent in the URL but I'm currently getting a progress bar saying "URL data transfer" that stays on the screen for a long time without doing anything.

I'm not sure why you would use case when choose is a better option.

17 hours ago, madman411 said:

http://10.0.1.90/state.xml?relayState=0

 

My wild guess is that your script should look like this

Insert from URL [ Select; With dialog: Off; "http://10.0.1.90/state.xml?relayState" & $desiredRelayState ]

 

Edited by ggt667
Link to post
Share on other sites
18 hours ago, ggt667 said:

I'm not sure why you would use case when choose is a better option.

When you make statements about what is better than an alternative, please qualify the statement.  Why is 'choose' better than IF() or CASE() for you?

If two or three different approaches produce the same result, how do you select the one you want to use?

Performance?  What if it doesn't matter and makes the code less readable?

  • Like 2
Link to post
Share on other sites
Posted (edited)

I'd say the conformity of the nature of the data will be clearer with the rigid choose() than the versatile case() conceptually speaking. Hence more readable.

Edited by ggt667
Link to post
Share on other sites
Posted (edited)

1. You don't know what the calculation does, so you are in no position to judge what is the "better option".

 

2. I would say that the simplest (and therefore best) way to implement a calculation that is meant to return either 0 or 1 is a Boolean statement. IOW, neither:

Case ( test ; 1 ; 0 )

nor:

Choose ( test ; 0 ; 1 )

but just:

test

or (if necessary):

GetAsBoolean ( test )

 

3. This is completely irrelevant to the question.

 

Edited by comment
  • Like 1
Link to post
Share on other sites
Posted (edited)

Or ```

Choose( GetAsBoolean( $desiredRelayState ); 1; 0 )

```

Edited by ggt667
Link to post
Share on other sites
Posted (edited)
26 minutes ago, ggt667 said:

Choose( GetAsBoolean( $desiredRelayState ); 1; 0 )

Yes, that conforms to the trend of "why make it simple, when it can be complicated" - which is so popular in the Filemaker community...

 

Edited by comment
  • Haha 1
Link to post
Share on other sites
Posted (edited)
1 hour ago, comment said:

Yes, that conforms to the trend of "why make it simple, when it can be complicated" - which is so popular in the Filemaker community...

 

Complicated how? Choosing a more declarative* apporach is a choice to avoid complicated usually. First you make sure the datatype using `GetAsBoolean()` then you delegate the outcome using `Choose()`; in which is FileMaker's equivalent of `switch`/`case` statement in other languages? For all practical reasons but `default:`. I'm not sure where you are able to complicate this? At least this is what I have to do in `c`/`cpp`/`swift` to avoid making assumptions. In FileMaker everything is text regardless and certain safety measures will have to be put in place.

In computer science, declarative programming is a programming paradigm — a style of building the structure and elements of computer programs — that expresses the logic of a computation without describing its control flow. 

Edited by ggt667
Link to post
Share on other sites
16 minutes ago, ggt667 said:

Complicated how?

Complicated in the sense that: 

not test

will do exactly the same thing in fewer evaluations, less code  and much more readable way.

And since I already said this is irrelevant to topic of this thread, I will end this discussion here. Except one more note:

20 minutes ago, ggt667 said:

In FileMaker everything is text

You could not be more wrong.

 

Link to post
Share on other sites
Posted (edited)
5 minutes ago, comment said:

Complicated in the sense that: 


not test

will do exactly the same thing in fewer evaluations, less code  and much more readable way.

And since I already said this is irrelevant to topic of this thread, I will end this discussion here. Except one more note:

You could not be more wrong.

 

First you write an example that is non-declarative and then you make a statement that makes no sense to me. Can I no longer import letters into Filemaker's number field? I just tried `S10000` is still valid number field content. Do you know what data types are?

Edited by ggt667
Link to post
Share on other sites
1 hour ago, ggt667 said:

Can I no longer import letters into Filemaker's number field?

 

That has nothing to do with data types, what that speaks to is that FM is permissive in that it does not prohibit the user from inputting the wrong data type into fields, it leaves it up to developer to put validation rules in place.

FM does NOT treat everything as text as you claimed.  Even a variable will maintain the correct data type of what you set into it, including container data.

Link to post
Share on other sites
1 hour ago, Wim Decorte said:

 

That has nothing to do with data types, what that speaks to is that FM is permissive in that it does not prohibit the user from inputting the wrong data type into fields, it leaves it up to developer to put validation rules in place.

FM does NOT treat everything as text as you claimed.  Even a variable will maintain the correct data type of what you set into it, including container data.

Interesting, how can I retrieve the data type from the object?

Link to post
Share on other sites
12 hours ago, ggt667 said:

how can I retrieve the data type from the object?

If it is a field: by querying the FileMaker_Fields metatable with executeSql(), or by using the FieldType() design function.

If it is a variable: you can't.  Much like other environments where you declare a variable 'untyped' by doing something like 'var myVariable', FM works the same.  Except that you don't have a TypeOf() equivalent.  As a developer you need to know what you put in the variable.  When in doubt just use the right GetAs...() function.

Link to post
Share on other sites

I hate to continue this, but:

47 minutes ago, Wim Decorte said:

If it is a field: by querying the FileMaker_Fields metatable with executeSql(), or by using the FieldType() design function.

Field type is not data type. As you yourself said, Filemaker permits inputting the wrong data type into fields.

 

Link to post
Share on other sites

That's right, but operations on the data in a field very often will force casting into underlying field's data type.  Which is why it is often important to know the field's data type so that you know what it is supposed to be.

Link to post
Share on other sites
9 minutes ago, Wim Decorte said:

operations on the data in a field very often will force casting into underlying field's data type. 

No, I don't think so. Operations will often (if not always) force casting into the type expected by the operation, regardless of the originating field's type.

 

Link to post
Share on other sites
  • 2 weeks later...

The major issue for me working on older European solutions; either as a basis or continuation. The possibility of , or . as decimal separator for number as a value. Obviously when I create a new solution I always follow the rules of mathematics using , as multiple number separator and . as decimal separator. However importing older data using `tr` could be confusing at times.

Edited by ggt667
Link to post
Share on other sites
53 minutes ago, ggt667 said:

I always follow the rules of mathematics using , as multiple number separator and . as decimal separator.

There is no such rule in mathematics. And you will find that standards vary. Even ISO 80000 (the international standard describing scientific and mathematical quantities and their units, published by the International Organization for Standardization) states that "the decimal mark is either a comma or a point on the line". 

And what does this have to do with anything in this thread?

 

Edited by comment
Link to post
Share on other sites
1 hour ago, comment said:

There is no such rule in mathematics. And you will find that standards vary. Even ISO 80000 (the international standard describing scientific and mathematical quantities and their units, published by the International Organization for Standardization) states that "the decimal mark is either a comma or a point on the line". 

Not sure where you learnt your mathematics, but to me ( 0.0, 2.0, 10.0 ) means 0 and 2 and 10 either as coordinates in a 3D field, or as a list.

In Scandivian standards the same thing would be written ( 0,0, 2,0, 10,0 )

1 hour ago, comment said:

And what does this have to do with anything in this thread?

Maybe there are no moderators on this forum? In my opinion this should be split up into 2 threads, but I have no such rights on here, and can not do this myself.

Link to post
Share on other sites
Guest
This topic is now closed to further replies.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.