Mapping unstructured schema elements into a structured - xslt

I just want to convert from this the hotel_info structure to the AvailableHotels structure: The hotel_info XML comes from a legacy SOAP web service and my goal is to the structure AvailableHotels ; The elements required from the hotel_info occur in various places
<hotel_info>
<AvailableHotels>
<hotel_1>
<hotelName_1>safd1</hotelName_1>
<booked_by>Taylor Volkes</booked_by>
<booking_id>sdf</booking_id>
</hotel_1>
<hotel_2>
<hotelName_1>safd2</hotelName_1>
<booked_by>Sam Volkes</booked_by>
<booking_id>sdf</booking_id>
</hotel_2>
</AvailableHotels>
<hotel_details>
<detail>
<hotelReference>hotel_1</hotelReference>
<reservation_complete>Yes</reservation_complete>
<hotelAddress1>sd</hotelAddress1>
<hotelAddress2>sd</hotelAddress2>
<hotelCity>sd</hotelCity>
<hotelState>sd</hotelCity>
<hotelState>AK</hotelState>
<suite_required>Yes</suite_required>
<email_provided>sdfeiwocmed</email_provided>
<hotelState__b_>HI</hotelState__b_>
</detail>
<detail>
<hotelReference>hotel_2</hotelReference>
<reservation_complete>Yes</reservation_complete>
<hotelAddress1>sd</hotelAddress1>
<hotelAddress2>sd</hotelAddress2>
<hotelCity>sd</hotelCity>
<hotelState>sd</hotelCity>
<hotelState>AK</hotelState>
<suite_required>Yes</suite_required>
<email_provided>sdfeiwocmed</email_provided>
<hotelState__b_>HI</hotelState__b_>
</detail>
</hotel_details>
<hotel_info>
To this:
<AvailableHotels>
<hotel>
<HotelName>hotel_1</HotelName>
<HotelAddressLine1Text></HotelAddressLine1Text>
<HotelAddressLine2Text></HotelAddressLine2Text>
<HotelCityName></HotelCityName>
<HotelStateCode></HotelStateCode>
<HotelZip5Code></HotelZip5Code>
<HotelZip4Code></HotelZip4Code>
<reservation_status>booked</reservation_status>
</hotel>
<hotel>
<HotelName>hotel_2</HotelName>
<HotelAddressLine1Text></HotelAddressLine1Text>
<HotelAddressLine2Text></HotelAddressLine2Text>
<HotelCityName></HotelCityName>
<HotelStateCode></HotelStateCode>
<HotelZip5Code></HotelZip5Code>
<reservation_status>booked</reservation_status>
<HotelZip4Code></HotelZip4Code>
</hotel>
</AvailableHotels>
How can I do this?

Step by step:
Create the output to render the AvailableHotels -hotel - HotelName part
create a variable curHotel with name() of the tags inside your AvailableHotels
use the parameter as selection criteria for apply-templates something along the lines of <xsl:apply-templates select="/hotel_info/hotel_details/detail[hotelReference=$curHotel]" />
(off my head, might contain typos)

Related

Create sub-tags in Matlab Soap request

I am developing a SOAP client in Matlab for connection a Web Service. What I am doing is the following script:
createClassFromWsdl('http://192.168.107.239/WSDL/v4.0/iLON100.wsdl')
obj = iLON100
methods(obj)
With the next result:
Methods for class iLON100:
Clear Get List Set display
Delete InvokeCmd Read Write iLON100
Then, I am editing for example the method List in order to request the list of Items for the service. The dot m file is:
% Build up the argument lists.
values = { '','//Item[#xsi:type="Dp_Cfg"]'};
names = { 'iLonItem','xSelect'};
types = {};
% Create the message, make the call, and convert the response into a variable.
soapMessage = createSoapMessage('http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/',
'List', values, names, types, 'document');
I have also a SOAP tester from the vendor of the device. Then, if I compare both XML requests, they differ as you can see in the next example (firstly the original request and secondly the Matlab one):
<SOAP-ENV:Body>
<List xmlns="http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/">
<iLonItem>
<xSelect>
//Item[#xsi:type="Dp_Cfg"]
</xSelect>
</iLonItem>
</List>
</SOAP-ENV:Body>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<List xmlns="http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/">
<iLonItem/>
<xSelect>Item</xSelect>
</List>
</soap:Body>
As you can observe, the tags are not included as sub-tags. I would like to know how to do it and generate the same structure of XML for sending the SOAP request correctly.
Thank you so much,
At the end, I have solved it by creating a structure as follows:
myStruct = struct('iLonItem',struct('xSelect','//Item[#xsi:type="Dp_Cfg"]'))
This structure is inserted into "values" and the method's name "iLONItem".

XmlDocument returned by web service as XmlNode, then XPath doesn't work?

I'm trying to utilise a web service/method which accepts an XmlDocument and returns an XmlDocument. When I add a reference to this web service to my C# application, the proxy code is defined to use XmlNodes instead of XmlDocuments. This seems fairly well recognised behaviour (but confirmation and/or an explanation would be nice - see SO here).
However, if I take the returned XmlNode object and try and do a simple XPath query to "SelectNodes(XPath)", I get no nodes found - but matching nodes do exist.
If, however, I take the OuterXml of the returned XmlNode, and create myself a new XmlDocument from it, my XPath query finds the nodes I expected.
Why is that ? What is it about the returned XmlDocument/XmlNode (or conversion between) that stops the XPath query from working as expected ?
Thanks.
Edit:
The Xml looks like this:
<Results xmlns="">
<Result>
:
<Success>True</Success>
</Result>
<Result>
:
<Success>False</Success>
</Result>
</Results>
...and the XPath looks like this...
Dim xPath As String = "//Result[Success='False']"
If (xmlResults.SelectNodes(xPath).Count > 0) Then
Throw New ApplicationException("Results returned indicate a problem:- " + xmlResults.OuterXml)
End If
One alternative to creating my own XmlDocument would be to use Linq, as per:
Dim results As XDocument = XDocument.Parse(xmlResults.OuterXml)
If (results.Descendants("Success").Count(Function(node) node.Value.ToLower() = "false") > 0) Then
Throw New ApplicationException("Results returned indicate a problem:- " + xmlResults.OuterXml)
End If

Reading an XML document using pugiXml

i have a problem with parsing an xml document using pugiXml, it seems to me that everything is correct but this code doesn't work :(
void MainWindow::open()
{
QString fileName = QFileDialog::getOpenFileName(this,"Open");
xml_document doc;
doc.load_file(fileName.toStdString().c_str());
for (pugi::xml_node node : doc.child("Person"))
{
qDebug(node.child_value("nom"));
qDebug(node.child_value("Age"));
}
}
Xml file format :
<?xml version="1.0"?>
<Persons>
<Person>
<nom>Med</nom>
<Age>12</Age>
</Person>
<Person>
<nom>Nasr</nom>
<Age>14</Age>
</Person>
<Person>
<nom>Souad</nom>
<Age>52</Age>
</Person>
</Persons>
The most probable cause is that you should use doc.child("Persons").
Document object in your case has one child Persons, that has several Person children. doc.child("Person") fails to find the node and returns a null handle.
Having said that, don't forget to check load_file return value as well.

XML Getting attibute value of a Node

I am using XML DOM API in C++ to parse an XML file. I can't find any method to get the attribute value in a node element.
For example, in the following xml
<test>
<fruit count="10">
...
...
</fruit>
<test>
I need to get the count string("10") using XML APIs. Can anybody help me with some code snippets.
Use DOM Parser API to get attribute value count.
Refer below sample code:
//code to perform some process for parsing the input file and get rootElement
DOMNodeList* fruitNodes= rootElement->getElementsByTagName(XMLString::transcode("fruit"));
DOMNode* node = fruitNodes->item(0);
DOMElement* fruitElement = dynamic_cast <xercesc::DOMElement*>(node);
const XMLCh* attrValue = fruitElement->getAttribute(XMLString::transcode("count"));
you can get value 10 from attrValue using: string(XMLString::transcode(attrValue))
Based on http://msdn.microsoft.com/en-us/library/windows/desktop/ms754523(v=vs.85).aspx
Try something like:
pXMLDomNodeList = pXMLDocElement->selectNodes("/test/fruit/#count");

C++ Boost Property Tree Update Existing Node By Attribute Qualifier

Ok, so here's a sample of the XML structure:
<config>
<Ignored>
<Ignore name="Test A">
<Criteria>
<value>actual value</value>
</Criteria>
</Ignore>
<Ignore name="Test B">
<Criteria>
<value>actual value</value>
</Criteria>
</Ignore>
</Ignored>
<config>
I would like to be able to do two things:
Perform a get directly to the Test A element without having to loop all Ignore elements..like a selector on an attribute.
If nothing else, I need a method of updating either of the Ignore elements and can't seem to figure it out
Do I have to delete the element and recreate it? I can't seem to figure out a way to perform a put which qualifies an element (where there a many with the same name at the same level) by an attribute (which would be unique at that level).
Something like:
pt.put("config.Ignored.Ignore.<xmlattr>.name='Test A'.Criteria.value",some_var)
Or anything else that can achieve the end goal. Thank you very much!
Full disclosure: I'm pretty new to C++ and may be missing something blatantly obvious.
Boost.property_tree xml parser (RapidXML) doesn't support this.
Consider using something like TinyXPath is you want such functionality out of the box.
Or use explicit loop to find Ignore node with required attribute. Then you can use
someIgnoreNode.put("Criteria.value", some_var);
you may use a method like:
auto & pt_child = pt.getchild("config.Ignored");
BOOST_FOREACH(ptree::value_type &v1, pt_child)
{
if (v1.first == Ignore && v1.second.get<std::string>("<xmlattr>.name") == "Test A")
{
ptree & ptGrandChild = v1.second;
ptGrandChild.put<std::string>("Criteria.value", some_var);
}
}
boost::property_tree::xml_writer_settings<std::string> settings =
boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
write_xml(xmlPath, pt, std::locale(), settings);