Update XML nodevalue with C++ - c++

I have an XML as below
<ROOT>
<Device>
<host>localhost</host>
<Port>52000</Port>
</Device>
<DeviceHost>
<Server>Server.exe</Server>
<Port>81</Port>
</DeviceHost>
<Settings>
<Flag1>100</Flag1>
<Flag2>2000</Flag2>
</Settings>
</ROOT>
How can I update the Flag1 and Flag2 to 200 and 4000 respectively without changing other values using VC++?
I have two function wrote using api MSXML.
doc.LoadXml(Data);//for loading the xml data
doc.Save(FilePath);//for saving the xml data
But my issue is before saving how can i update two node values

You would need to get the correct node by calling getElementsByTagName (which should return a NodeList containing one item) and then call put_nodeValue to write the value -- there are some MSDN samples here and here
EDIT: you should also be able to use doc.selectSingleNode("/ROOT/Flag1", &pNode) as per this MSDN article

Related

DataSink step to return each response with all the children

I learnt very recently how to use data-driven testing in Ready API and loop calls based on the data. My goal is to run the steps in loop and at the end create an auto-export facility with DataSink so that the results get auto exported.
Now when I try go to DataSink, as I understood I need to create column headers as below
to store the corresponding child values
It would work well, if the soap response for each of the siteId has the same XML structure. But in my case each of the 2000+ response that I get has different number of children within
<retrun> </return>
For e.g. please take a look at the response 1 and response 2. Both these responses have different number of children.
Response 1
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getSiteInfoResponse xmlns:ns2="http://billing.xyz.cc/">
<return>
<address1>A</address1>
<city>B</city>
<closeDate>2018-10-15T00:00:00-05:00</closeDate>
<contact1/>
<contact2>TBD</contact2>
<country>X1</country>
<customerNbr>288</customerNbr>
<emailAddr1/>
<emailAddr2/>
<fax1>0</fax1>
<fax2>0</fax2>
<gps>C</gps>
<grouping2>Leased</grouping2>
<grouping4>D</grouping4>
<jobTitle1/>
<jobTitle2/>
<phone1>0</phone1>
<phone2>0</phone2>
<siteId>862578</siteId>
<siteName>D</siteName>
<squareFoot>0.0</squareFoot>
<state>E</state>
<weatherStation>D</weatherStation>
<zip4>4</zip4>
<zip5>F</zip5>
</return>
</ns2:getSiteInfoResponse>
</soap:Body>
</soap:Envelope>
Response 2
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getSiteInfoResponse xmlns:ns2="http://billing.xyz.cc/">
<return>
<address1>1202</address1>
<city>QA</city>
<contact1/>
<contact2>BL</contact2>
<country>A</country>
<customerNbr>288</customerNbr>
<emailAddr1/>
<emailAddr2/>
<fax1>0</fax1>
<fax2>0</fax2>
<gps>LTE</gps>
<grouping1>1345</grouping1>
<grouping2>Leased</grouping2>
<grouping3>ZX</grouping3>
<grouping4>AA</grouping4>
<grouping5>2000</grouping5>
<jobTitle1/>
<jobTitle2/>
<phone1>0</phone1>
<phone2>0</phone2>
<services>
<accountNbr>11099942</accountNbr>
<liveDt>2013-07-01T00:00:00-05:00</liveDt>
<service>2</service>
<serviceType>gas</serviceType>
<vendorAddr1/>
<vendorAddr2>M</vendorAddr2>
<vendorCity>N</vendorCity>
<vendorName>O</vendorName>
<vendorNbr>P</vendorNbr>
<vendorPhone>Q</vendorPhone>
<vendorState>R</vendorState>
<vendorZip>S</vendorZip>
</services>
<services>
<accountNbr>13064944</accountNbr>
<liveDt>2018-05-20T00:00:00-05:00</liveDt>
<service>2</service>
<serviceType>gas</serviceType>
<vendorAddr1/>
<vendorAddr2>A</vendorAddr2>
<vendorCity>B</vendorCity>
<vendorName>C</vendorName>
<vendorNbr>677</vendorNbr>
<vendorPhone>D</vendorPhone>
<vendorState>E</vendorState>
<vendorZip>F</vendorZip>
</services>
<siteId>101567</siteId>
<siteName>X</siteName>
<squareFoot>4226.0</squareFoot>
<state>Y</state>
<weatherStation>Z</weatherStation>
<zip4>0</zip4>
<zip5>L</zip5>
</return>
</ns2:getSiteInfoResponse>
</soap:Body>
</soap:Envelope>
Now, I need to further create a table using the whole response to be utilized in business intelligence. If I have to create matching headers in DataSink I need to go through each and every responses to ensure that I have created a corresponding property in datasink. It is not humanly possible without compromising the accuracy.
Is there any way to program Ready API to store individual XML response by each looping call in a file specified by me (2000+ XML responses) or to store all the values by children of the response node without needing me to specify all the header names in the DataSink window. If it happens, i will be fine in both cases to utilize a BI tool to create a corresponding table from there.
Thank you in advance.
As you point out, the differing number of children makes the linear data sink problematic.
That said, you can still use datasink to dump out all values in one go. In the datasink, create a single header and use 'get data' to select the root node of your response.
This will obviously generate a massive file, so you have two choices here. Either dump everything into a single file, or you could create a new file per response
If you're wondering about naming of lots of little files, you can generate a filename on the fly for the data sink to use. To do this, create a groovy script inside the loop. In this script, make it return a path and the file name. You could use some timestamp value, e.g. c:\temp\myResults\2020120218150102.txt, which is year, month, data, hour, min seconds and ms. Then, in the Data sink step where you browse for the file name, use get data to 'grab' the result of the groovy script.
#Chris Adams thanks for your awesome idea. Even though I could not completely put this into practice. But because of your idea (Get Data) I took a different route and I got what I wanted.
So this is what I did. Instead of using DataSink I used create file. The idea is whenever I schedule this task the Ready API can run the whole thing in loop and throw the result in a static folder
with file name
containing
site Id obtained from Get Data Raw request agr3
${getSiteInfo#RawRequest#declare namespace bil='http://billing.xyz.cc/'; //bil:getSiteInfo[1]/arg3[1]}.xml
and
file content
with whole response from root node Response
${getSiteInfo#Response#declare namespace soap='http://schemas.xmlsoap.org/soap/envelope/'; //soap:Envelope[1]}
The end result is this
However, I am still interested in this and I could get this part to work.
That said, you can still use datasink to dump out all values in one go. In the datasink, create a single header and use 'get data' to select the root node of your response.

Add entire xml node to an element using lxml

I am trying to add new nodes to an element tree. These new nodes have childs in them. Is there anyway using lxml to add all these in one go.
Ex:
Old format
<Test>
<Header>
</Header>
</Test>
New format that I am trying to achieve by adding nodes
<Test>
<Header>
<Source>
<ProcessID> 234 </ProcessID>
<InstanceID> 1 </InstanceID>
</Source>
<Target>
<ProcessID> 234 </ProcessID>
<InstanceID> 1 </InstanceID>
</Target>
</Header>
</Test>
I am looking for 2 things:
1) Is there anyway by which I can add entire Source node and Target node in one go? I mean adding source node in one go and Target node in one go. Instead of adding source node and then processID and then InstanceID etc
2) At the moment I am maintaining changes in a flat file and storing the changes and then applying them using lxml
The problem I am facing is,
When I add Source node to Header node using Subelement it is not added as proper tag and only closure tag of Source is added. When I try to get Source element using find function I am getting element as null. Hence I can't add childs to Source node. As you can see Source node doesn't have any attributes or text, but it has childs.
Can you help me in adding this structure to element tree? I tried all the ways as much as I can. I am sure there should be a simple solution to do this instead of adding it one by one.
I have so many files to be treated like this, so looking for a simple solution.
TIA

Using XSLT to transform ReqIF to UML

I'm trying to transform one XML document (REQ-IF) into another XML document (UML-Class-Diagram document) using XSLT.
My Problem now is the following:
REQ-IF provides datatypes as:
<Datatypes>
<DATATYPE-DEFINITION-STRING IDENTIFIER="xyz" LONG-NAME="ABC"
</Datatypes>
and Objects as:
<SPEC-OBJECTS>
<VALUES>
<ATTRIBUTE-VALUE-STRING THE-VALUE="some-value">
<DEFINITION>
<ATTRIBUTE-DEFINITION-STRING-REF>xyz</ATTRIBUTE-DEFINITION-STRING-REF>
</DEFINITION>
</ATTRIBUTE-VALUE-STRING>
</VALUES
<SPEC-OBJECTS>
This is resembled in my UML representation as:
<ownedAttribute xmi:id="some-ID" name="ABC" type="some-ID">
please note the ABC and xyz.
I therefore use <xsl:for-each> to loop through the Objects and another <xsl:for-each> to loop through the values.
Now I have to take the Datatype-ID from the value, find out which Datatype it is and write the Datatype-name into the output file.
How do I do that?
Thank you so much in advance
Try /Datatypes[DATATYPE-DEFINITION-STRING/#IDENTIFIER = current()/ATTRIBUTE-VALUE-STRING/DEFINITION/ATTRIBUTE-DEFINITION-STRING-REF]/DATATYPE-DEFINITION-STRING/#LONG-NAME.
I admit I didn't actually test this, but you'll probably get the idea. The point of current is to access the XSLT context (the VALUES element) as opposed to the current XPath context that is active in the filter.

XSLT 2.0: Limit the ancestor axes to a certain element/s level up the document tree

I'm seeing a quite odd behaviour, when trying to limit the results given by applying ancestor::* to an element I always get an extra ancestor although is expressly excluded by the predicate.
Here the code:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<level_a>
<level_b>
<level_c>
<level_d>
<level_e/>
</level_d>
</level_c>
</level_b>
</level_a>
<level_b>
<level_c>
<level_d>
<level_d>
<level_e/>
</level_d>
</level_d>
</level_c>
</level_b>
</root>
XPath:
(//level_d[not(level_d)])[last()]/ancestor::*[level_c|level_b]
so basically I'm selecting the level_d elements that doesn't have another level_d element nested, getting the last one of them and trying to get all the ancestors up to element level_b.
But the result I'm seeing using Altova XMLSpy 2011 is:
level_a
level_b
I don't quite understand why I'm getting that result and how can I improve my xpath to limit effectively the ancestors up to level_b (i.e. level_c and level_b).
Any hint is greatly appreciated!
Regards
Vlax
Well ancestor::*[level_c|level_b] selects all elements on the ancestor axis that have a level_c or level_b child.
You might want (//level_d[not(level_d)])[last()]/ancestor::*[self::level_c|self::level_b].
Or with your textual description "to limit effectively the ancestors to level_b" you simply want (//level_d[not(level_d)])[last()]/ancestor::level_b.
I think you get right result because clause ancestor::*[level_c|level_b] I read as "all ancestors containing element level_b or level_c". So, level_b is ok because it contains level_c and level_a is ok too because it contains level_b.
So if I change your XPath into (//level_d[not(level_d)])[last()]/ancestor::*[level_c] it results into level_b only.
Probably it is not exactly what you asking for but I'm not sure if I understand well the purpose of your XPath :-)

XSLT Transformation requires counts

Hello I am transforming a csv file using XSLT files to pull training records out by employees.
What I know need to do is also pull a footer on the bottom of the CSV file with the total record count and somehow count each record that is transformed so I can do a compare of these in the system I am importing these into.
This is what the source file looks like -
TrainingRecord,,SP Training,,geoff.culbertson,,Trained,,IT
TrainingRecord,,SP Training,,jim.schultz,,Trained,,IT
RecordCount|2
So I need to transform the Record Count at the end of the file and do a count for each record in this example it would be 2 and transform that so I can do a compare.
It seems very strange to use XSLT with a CSV as the input, but to answer your question, but based on the XSLT you've provided us, I believe you could obtain the row count with:
<xsl:value-of select="count(//Line)" />