Dynamic XPath Creation in SQL Server - xpath

I have an XML and I want to get the Xml Node values dynamically. I want to Pass the Node Name and the in return the function or SP should return me the value of that Node.
<ClassificationTypeEntity>
<LTABLE_ID>3170</LTABLE_ID>
<LTABLE_CODE>script Code</LTABLE_CODE>
<LTABLE_DESC>alert(''hello'')</LTABLE_DESC>
<ACTIVE_YES_NO>1</ACTIVE_YES_NO>enter code here
<PRIVATE_FILING>0</PRIVATE_FILING>
<RETENTION_CODE /><RETENTION_TITLE />
<LTABLE_ID_P>0</LTABLE_ID_P>
</ClassificationTypeEntity>;
For Example, In the above xml, when I want the value of LTABLE_CODE Node, I will pass the same and the result should I get is
script code
Same for LTABLE_DESC the result should be alert(''hello'')
However I can write the 2 Xpath query for both but in case my schema gets changed (more properties added or removed) then I will have to change my SP also.
Thanks,
Mohit Jain

Thanks for your replies.
I have found the solution:
declare #xmlData xml, #NodeName VarChar(500), #nodeValue VarChar(500)
Set #NodeName = 'LTABLE_CODE';
--Set #NodeName = 'LTABLE_DESC';
set #xmlData =
'<ClassificationTypeEntity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<LTABLE_ID>3170</LTABLE_ID>
<LTABLE_CODE><script>al</LTABLE_CODE>
<LTABLE_DESC><script>alert(''hello'')</script></LTABLE_DESC>
<ACTIVE_YES_NO>1</ACTIVE_YES_NO>
<PRIVATE_FILING>0</PRIVATE_FILING>
<RETENTION_CODE /><RETENTION_TITLE />
<LTABLE_ID_P>0</LTABLE_ID_P>
</ClassificationTypeEntity>'
SET #nodeValue = #xmlData.value('(/ClassificationTypeEntity/*[local-name()=sql:variable("#NodeName")])[1]','nvarchar(max)')
SELECT #nodeValue

Related

Fetch value from XML using dynamic tag in ESQL

I have an xml
<family>
<child_one>ROY</child_one>
<child_two>VIC</child_two>
</family>
I want to fetch the value from the XML based on the dynamic tag in ESQL. I have tried like this
SET dynamicTag = 'child_'||num;
SET value = InputRoot.XMLNSC.parent.(XML.Element)dynamicTag;
Here num is the value received from the input it can be one or two. The result should be value = ROY if num is one and value is VIC if num is two.
The chapter ESQL field reference overview describes this use case:
Because the names of the fields appear in the ESQL program, they must be known when the program is written. This limitation can be avoided by using the alternative syntax that uses braces ( { ... } ).
So can change your code like this:
SET value = InputRoot.XMLNSC.parent.(XMLNSC.Element){dynamicTag};
Notice the change of the element type as well, see comment of #kimbert.

UFT API -- "Select data" How to return values for query to Sybase database

I have to validate an API output with a values stored in Sybase DB.
When I use "select Data" activity to fetch the value from Sybase table, the value is returned in XML format as below:
<Row>
<ColumnName1> Value </ColumnName1>
<ColumnName2> Value </ColumnName2>
<ColumnName3> Value </ColumnName3>
</Row>
However I need only the Value so I can save it in excel to compare in my next step. Comparison is being done on value basis not with xml. I need to convert the response from select data (which is in XML format shown above) .
The subsequent checkpoint in API output fails as I need to provide individual values as input to the service.
I will need a solution that can either split array and give me individual values at run time Or I should be able to save values in Excel which I can save and import at run time.
You can use the COM object for Microsoft's XML Parser. Something like this should do it,
set objXml = CreateObject("Microsoft.XMLDOM")
objXml.Load("C:\yourxmlpath.xml")
' Get your node (you can traverse it like a path)
set allMathchingRows = objXml.selectNodes("/Row")
For intRow = 0 To allMathchingRows.Length - 1
For each Node in allMathchingRows(intRow).ChildNodes
strAllRowData = strAllRowData + "," + Node.text
Next
' Remove the ' appended to the start of string
strAllRowData = Right(strAllRowData, Len(strAllRowData) - 1)
Next
you may want to refine it more if you want your data separate for each rows

Insert xml Node into a CLOB column with namespace in Oracle

I have next below xml value in CLOB column in Oracle 11g.
<Energy xmlns="http://euroconsumers.org/notifications/2009/01/notification">
<WEBSITE>WWW.VERLAAG.BE</WEBSITE>
<CUSTOMERID>xxxxxx</CUSTOMERID>
<Gender>M</Gender>
<Telephone>0000000000</Telephone>
</Energy>
I want to add a new node called: Language
to look like this:
<Energy xmlns="http://euroconsumers.org/notifications/2009/01/notification">
<WEBSITE>WWW.VERLAAG.BE</WEBSITE>
<CUSTOMERID>xxxxxx</CUSTOMERID>
<Gender>M</Gender>
<Telephone>0000000000</Telephone>
<Language></Language>
</Energy>
I've used next below sentence:
update tmp_tab_noemail_test_aankoop p1
set p1.sce_msg = insertchildxml(p1.sce_msg, '/Energy', 'Language',
xmltype('<Language><Language/>'),
'xmlns="http://euroconsumers.org/notifications/2009/01/notification')
.getclobval();
And also this one:
update tmp_tab_noemail_test_aankoop p1
set p1.sce_msg = APPENDCHILDXML(p1.sce_msg,
'/Energy',
XMLType('<Language><Language/>'),
'xmlns="http://euroconsumers.org/notifications/2009/01/notification')
.getclobval()
But any of these functions are working.
Any idea?
In both of your statements you are not converting your initial CLOB to XMLType, and your closing tag for the new node is malformed - you have <Language/> instead of </Language>. Either provide opening and closing tags, or a single self-closing one, not a mix of both. You're also missing the closing double-quote in your namespace.
These both work:
update tmp_tab_noemail_test_aankoop p1
set p1.sce_msg = insertchildxml(XMLType(p1.sce_msg), '/Energy', 'Language',
XMLType('<Language></Language>'),
'xmlns="http://euroconsumers.org/notifications/2009/01/notification"').getclobval();
Or:
update tmp_tab_noemail_test_aankoop p1
set p1.sce_msg = APPENDCHILDXML(XMLType(p1.sce_msg), '/Energy',
XMLType('<Language></Language>'),
'xmlns="http://euroconsumers.org/notifications/2009/01/notification"').getclobval();
The latter looks a little better as the new tag appears as
<Language/>
rather than
<Language xmlns=""/>
You can preserve the namespace with insertchild but then it appears explicitly in the new node even though it matches the top-level Energy namespace; which doesn't matter functionally but looks a bit odd.

Compare two xml files using VBS in QTP

I need to compare 2 xml files using QTP where the values for each tag needs to be compared and need to print the difference in values if found. I used the built in Function XMLUTIL but its not working as expected i.e.. its creates a file with differences including the parent tag.
<tns:AAL_Request_NEW xsi:schemaLocation="http://www.bnymellon.com/AAL_Request_NEW AAL_Request_NEW.xsd">
<tns:OPF_Information>
<tns:Source>
<tns:Source>EPH</tns:Source>
</tns:Source>
<tns:References>
<tns:Accounting_Record_Reference>130830000672401</tns:Accounting_Record_Reference>
<tns:OPF_Reference>EPH1308300006724</tns:OPF_Reference>
<tns:Group_Reference>EPH1308300006723</tns:Group_Reference>
</tns:References>
</tns:OPF_Information>
</tns:AAL_Request_NEW>
In the above xml file i just need the tags with values like
tns:Source with value EPH, tns:Accounting_Record_Reference with value 130830000672401, tns:OPF_Reference with value EPH1308300006724 and tns:Group_Reference EPH1308300006723 to be compared and not the parent tags like tns:References, tns:OPF_Information or tns:AAL_Request_NEW.
Can anyone help with the logic to fetch the tags which has no child tag inside it and ends immediately with having only a value between its start <> and end and compare it with the other file and print the tag name and the values if there is a difference?
you can use CreateObject("Microsoft.XMLDOM") to read the xml files and retrive the tags by tag name and comparte them both.
Set objXMLDoc = CreateObject("Microsoft.XMLDOM")
objXMLDoc.async = False
objXMLDoc.load("<XML PATH>")
Set Root = objXMLDoc.documentElement
Set tags = root.tagnames
Set NodeList = Root.getElementsByTagname("<node name>")
For Each Elem In NodeList
msgbox Elem.text
Next
Thanks and regards

Inserting a child node when list is empty (XForms)

My problem is the following :
I usually have those data:
<structures>
<structure id="10">
<code>XXX</code>
</structure>
</structures>
so the table I display (single columns : code) is ok.
But in some cases, the data is the result a a query with no content, so the data is:
<structures/>
resulting in my table not displaying + error.
I am trying to insert, in the case of an empty instance, a single node so that the data would look like:
<structures>
<structure id="0"/>
</structures>
I am trying something like that :
<xforms:action ev:event="xforms-submit-done">
<xforms:insert if="0 = count(instance('{./instance-name}')/root/node())" context="instance('{./instance-name}')/root/node()" origin="xforms:element('structure', '')" />
</xforms:action>
but no node inserted when I look at the data in the inspector in the page.
Any obvious thing I am doing wrong?
There seems to be erros in your XPath if and context expressions:
if="0 = count(instance('{./instance-name}')/root/node())"
context="instance('{./instance-name}')/root/node()"
You are a using curly brackets { and }, I assume to have the behavior of attribute value templates (AVTs). But the if and context expressions are already XPath expressions, so you cannot use AVTs in them. Try instead:
if="0 = count(instance(instance-name)/root/node())"
context="instance(instance-name)/root/node()"
Also, the instance-name path is relative to something which might not be clear when reading or writing the expression. I would suggest using an absolute path for example instance('foo')/instance-name to make things clearer.
You don't provide the structure of the other instances, so I can tell for sure, but you'll expression above suppose that they have the form:
<xf:instance id="foo">
<some-root-element>
<root>
<structure/>
</root>
<some-root-element>
</xf:instance>
I don't know if that's what you intend.
Finally, you could replace count(something) = 0, with empty(something).

Resources