The community will undergo maintenance on October 16th at 10:00 PM PDT and will be unavailable for up to one hour.
Recently I needed to be able to parse and handle XML data natively inside of a ThingWorx script, and this XML file happened to have a SOAP namespace as well. I learned a few things along the way that I couldn’t find a lot of documentation on, so am sharing here.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" headers="">
<SOAP-ENV:Body>
<get_part_schResponse xmlns="urn:schemas-iwaysoftware-com:iwse">
<get_part_schResult>
<get_part_schRow>
<PART_NO>123456</PART_NO>
<ORD_PROC_DIV_CD>E</ORD_PROC_DIV_CD>
<MFG_DIV_CD>E</MFG_DIV_CD>
<SCHED_DT>2020-01-01</SCHED_DT>
</get_part_schRow>
<get_part_schRow>
<PART_NO>789456</PART_NO>
<ORD_PROC_DIV_CD>E</ORD_PROC_DIV_CD>
<MFG_DIV_CD>E</MFG_DIV_CD>
<SCHED_DT>2020-01-01</SCHED_DT>
</get_part_schRow>
</get_part_schResult>
</get_part_schResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
var data = resultXML.*::Body.*::get_part_schResponse.*::get_part_schResult.*;
var result = String(data);
for each (var row in data) {
result.AddRow({
PartNumber: row.*::PART_NO,
OrderProcessingDivCD: row.*::ORD_PROC_DIV_CD,
ManufacturingDivCD: row.*::MFG_DIV_CD,
ScheduledDate: row.*::SCHED_DT
});
}
Very cool. should also add the @ part as well when you have multiple elements within a row.
i,
Does this code still working ?
var data = resultXML.*::Body.*::get_part_schResponse.*::get_part_schResult.*;
If yes, should i add something to make it work ?
I think the example was developed on Thingworx 8.x not sure what version you are using, but it should still be valid.
Yes, it was developed in 8.5.3. As mentioned in the original post, you will get Linting warnings but it does actually work. I have not tested on any newer versions 8.5.3, but the Rhino engine hasn't changed versions, so I would assume it still works.
I recently needed to get some properties from a Kepware Complex Update (it's under Advanced Tags) and needed a little simpler of an example than what's in the original post.
Here's the XML:
<ComplexUpdate>
<Item>
<Name>DCToolCh1.DCToolDev1.LTR.LTR_ID</Name>
<Value DataType="5">38164</Value>
<Quality>192</Quality>
<TimeStamp>132621347700044322</TimeStamp>
</Item>
<Item>
<Name>DCToolCh1.DCToolDev1.LTR.LTR_TIMESTAMP</Name>
<Value DataType="8">4/5/2021 10:19:30 PM</Value>
<Quality>192</Quality>
<TimeStamp>132621347700044322</TimeStamp>
</Item>
<Item>
<Name>DCToolCh1.DCToolDev1.LTR.LTR_TORQUE_VALUE</Name>
<Value DataType="5">2.25</Value>
<Quality>192</Quality>
<TimeStamp>132621347700044322</TimeStamp>
</Item>
<Item>
<Name>DCToolCh1.DCToolDev1.LTR.LTR_TORQUE_STATUS</Name>
<Value DataType="5">0</Value>
<Quality>192</Quality>
<TimeStamp>132621347700044322</TimeStamp>
</Item>
<Item>
<Name>DCToolCh1.DCToolDev1.TOOLDATA.TOOLDATA_TSERIAL</Name>
<Value DataType="8">238FH0929</Value>
<Quality>192</Quality>
<TimeStamp>132621347700044322</TimeStamp>
</Item>
</ComplexUpdate>
Note that the TimeStamp is a Windows file time, which is not the same as Unix epoch (but similar). My code doesn't parse that at the moment, but it is something that could be done.
Also something I learned since I initially posted is that you can add jshint comments in to help with the linting issues with E4X (and I added the moz: true to stop getting warnings with my for each loop).
Here's the code to take that XML and return it as an InfoTable:
// jshint moz: true
// me.ComplexUpdate is a Kepware-bound property that is getting in the XML bundle
let complexUpdate = new XML(me.ComplexUpdate);
// jshint ignore:start
let items = complexUpdate.*;
// jshint ignore:end
// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(TS.Kepware.ComplexUpdate_DS)
let result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TS.Kepware.ComplexUpdate_DS"
});
// load the XML up into an InfoTable structure
for each (let item in items) {
result.AddRow({
Name: item.Name,
Value: item.Value,
// jshint ignore:start
ValueDataType: parseInt(item.Value.@DataType),
// jshint ignore:end
Quality: parseInt(item.Quality),
TimeStamp: parseInt(item.TimeStamp)
});
}
Hope these examples help someone!
Here's a small service you can use to convert XML to object or JSON without having to touch E4X.