Continuous XML Parsing into Memory Tags

I have a RFID device that talks through TCP. I got the read data tied into a tag, but the value comes out as an XML text. Being new to ignition and python scripting, I am not entirely sure how to approach this. My initial thought is to parse through the data and store it as memory tags. I want to be able to store “device id”, “epc”, and “ts” from this XML file whenever the RFID reader reads a RFID tag:

ADVANNET/1.0
Content-Length:955
Content-Type:text/xml

<?xml version="1.0" encoding="UTF-8"?>
<inventory>
	<type>inventory</type>
	<ts>1519314110000</ts>
	<status>OK</status>
	<msg-version>2.3.0</msg-version>
	<op>inventory</op>
	<data>
		<advanNetId>AdvanNet-instance-98:84:e3:98:91:a3--1</advanNetId>
		<deviceId>testing</deviceId>
		<inventory>
			<class>INVENTORY</class>
			<deviceId>testing</deviceId>
			<size>1</size>
			<items>
				<item>
					<class>READ_EVENT</class>
					<epc>e2002080801302511000b324</epc>
					<ts>1519314110571</ts>
					<deviceId>testing</deviceId>
					<data>
						<class>TAG_DATA</class>
						<hexepc>e2002080801302511000b324</hexepc>
						<props>
							<prop>TIME_STAMP:1519314110571,</prop>
							<prop>RSSI:-53,</prop>
							<prop>RF_PHASE:143,</prop>
							<prop>ANTENNA_PORT:1,</prop>
							<prop>MUX1:0,</prop>
							<prop>MUX2:0,</prop>
							<prop>FREQ:867341,</prop>
						</props>
					</data>
				</item>
			</items>
		</inventory>
	</data>
</inventory>

Per this guide from ignition, I’ve attempted this code:

from xml.dom.minidom import parseString

Value = system.tag.read("RFID\New Tag").value
Value = Value.replace("ADVANNET/1.0", "")
Value = Value.replace("Content-Length:955", "")
Value = Value.replace("Content-Type:text/xml", "")
Value = Value.replace('<?xml version="1.0" encoding="UTF-8"?>', '')
print Value
dom = parseString(Value)
xmlTags = dom.getElementsByTagName('inventory')
xmlData = []
for tag in xmlTags:
	xmlData.append(tag.firstChild.data)

stuff = dom.getElementsByTagName('deviceID')
print stuff

I don’t think it’s working the way I want it to. So the questions are:
* How could I parse through the XML and store as memory tags?
* How could I let this script run every time a new XML data is read?
* Is there a simpler approach? Am I going about it the wrong way?

Any help is appreciated: guides, tips, videos, etc.

I haven’t tried this before, but I found this:

https://docs.inductiveautomation.com/display/DOC79/Parsing+XML+with+the+Etree+Library

I was able to use etree to parse out only the lowest <item> nodes values (since node names repeat in your devices returned xml doc). I had to change your tag reference to the multi-line string variable named ‘document’, but this should give the idea:

document = """
ADVANNET/1.0
Content-Length:955
Content-Type:text/xml

<?xml version="1.0" encoding="UTF-8"?>
<inventory>
	<type>inventory</type>
	<ts>1519314110000</ts>
	<status>OK</status>
	<msg-version>2.3.0</msg-version>
	<op>inventory</op>
	<data>
		<advanNetId>AdvanNet-instance-98:84:e3:98:91:a3--1</advanNetId>
		<deviceId>testing</deviceId>
		<inventory>
			<class>INVENTORY</class>
			<deviceId>testing</deviceId>
			<size>1</size>
			<items>
				<item>
					<class>READ_EVENT</class>
					<epc>e2002080801302511000b324</epc>
					<ts>1519314110571</ts>
					<deviceId>testing</deviceId>
					<data>
						<class>TAG_DATA</class>
						<hexepc>e2002080801302511000b324</hexepc>
						<props>
							<prop>TIME_STAMP:1519314110571,</prop>
							<prop>RSSI:-53,</prop>
							<prop>RF_PHASE:143,</prop>
							<prop>ANTENNA_PORT:1,</prop>
							<prop>MUX1:0,</prop>
							<prop>MUX2:0,</prop>
							<prop>FREQ:867341,</prop>
						</props>
					</data>
				</item>
			</items>
		</inventory>
	</data>
</inventory>
"""

import xml.etree.ElementTree as ET

declaration = '<?xml version="1.0" encoding="UTF-8"?>\n'
document = document.split(declaration)[1]
root = ET.fromstring(document)

for inventory in root.find('data/inventory/items/item'):
	for node in inventory.getiterator():
		if node.tag == 'deviceId':
			print node.tag, node.text
		elif node.tag == 'epc':
			print node.tag, node.text
		elif node.tag == 'ts':
			print node.tag, node.text

First we split() the XML document on the predefined declaration string, and select the second item (at index 1) to get rid of the declaration strings, instead of using replace() for each line. Then use the etree library to parse the string into an easily navigable document object, ‘root’. Then use root.find() to grab only the lowest-child item node, which is necessary since you have multiple definitions of ‘data’ and ‘inventory’. Of the items at that node, pull out the ones you need and do something with their text values.

In the above where I’m printing the node tag and text, you could easily just write back to predefined tags for those values. You should implement this in the OnValueChange event script of your XML tag.

When the XML data changes->parse out the new data->write to your new tags for deviceId, epc, and ts.

1 Like