Vous êtes sur la page 1sur 8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

How do you appy 2nd xpath query to DOM Node object obtained from xpath query of XMLDocument in ServiceNow JavaScript scripting?
Platform: ServiceNow Language: JavaScript / XML Use case: 1. XMLDocument instantiated from raw XML string 2. XPath query of XMLDocument returns DOM Node object 3. How do you further XPath query the DOM Node object? Question(s): How do you apply additional xpath query to results from another xpath query? How do you convert DOM Node object back to raw XML string? How do you convert DOM Node object to XMLDocument object? How do you convert XMLDocument object to raw XML string?

Thank you for your reply. This is an acceptable solution for a one-off script with the specific XML structure, however if the "details" node changes (ie nodes are located a couple of levels down) then we have to reprogram. An ideal solution would allow us to use xpath queries for everything - ie specify a root xpath (to get <details>) and specify one or more xpath sub-queries for the data. The only thing that changes is one or more xpaths and the code doesn't have to change. So per our question 1. If we execute the main xpath query to retrieve <details> nodes, can you please explain how to create an intermediate XMLDocument object from a node to drill down with an xpath sub-query? Also, 2. If we execute an xpath query that returns a node, how can we reference the node's parent? We do not see a ".parent" method or similar. Thanks again

Support I went through your code, and if I were you, probably I wouldn't solve the problem this way. I think the easier way would be to query the "/deviceManagementWebServiceResponse/devices/*" via xpath Loop through each device to first get the 'uuid' (simple child access of a Node object), and then the 'details' via a nodelist access to get individual key, values.
1/8

file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

This way you already have the uuid when you access the key field in devices. I think the code is unnecessarily complex right now, and by doing the above change you will not have to create intermediate XMLDocument objects just for xpath query. Unfortunately, I can only suggest this as part of my scope of work, and you will have to work on the solution yourself or you could engage my colleagues in Professional Service; who are experienced in writing custom scripts. Thank you, Support I endeavor to assist you with this issue, however this is a custom script, and not supported OOB. For your use case, I'll try to test the script tonight, and update you once I'm able to execute it on my local environment. I would really appreciate if you could attach the XML document on which the script is being tested along with the testXPath() script for me. Thank you, Developer We have had a difficult time getting our script to work without the ability to use xpath on a node. Developer I tried sending sample code in my previous message, but the indentation was not preserved so reading the code might be a little hard. Below is the sample code with indentation preserved (just replace all "~" character with " ", to run in the freeform script editor). Here is my question again: In the code below we need to retrieve the values for each device (children of the <devices> node. Most of these fields are stored as key/value pairs where the <key> node contains the field name and the <value> node contains the value. Each <device> node corresponds to a single record with the <uuid> tag containing the primary key. So we tried querying all the devices with the following xpath qurey: /deviceManagementWebServiceResponse/devices/* and we could read the nodes directly under <device>. However attempting to retrieve the name/value pairs for each with node the xpath query: /details/entry/ is not working. The wiki is not clear on whether a "node" returned by xmlDoc.getNodes is itself a DOM Node object, or some other type of object. Therefore we are unsure whether it is not working because we are using the wrong type of object, or whether our xpath syntax is wrong. We tried a different method to solve the problem, by querying all the <entry> tags in the XML: /deviceManagementWebServiceResponse/devices/device/details/* This gives us all the key/value pairs and we can loop through those. However, in order to use the key/value, we need the record ID (stored a couple of levels up in the <uuid> node). To access that node, we tried using an xpath query that references the <entry> node's great-grandparent's child <uuid>, which could give us the UUID: ../../../uuid However this isn't returning any values. (Also we are unclear whether this would be the UUID of the current <entry> node or just the first <UUID> it finds.)
file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java 2/8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

Any help would be appreciated. testXPath(); function testXPath() { ~~~~var strResult = ""; ~~~~var strErrors = ""; ~~~~var iErrorCount = 0; ~~~~var xmlString = this.get_XML_String(); ~~~~var xmlDoc = new XMLDocument(xmlString); ~~~~var xPathQuery = "/deviceManagementWebServiceResponse/devices/device/details/*"; ~~~~var xmlNodes = xmlDoc.getNodes(xPathQuery); ~~~~var xmlEntryNode, xmlUuidNode, strKey, strValue, strUUID; ~~~~for (var iLoop1 = 0; iLoop1 < xmlNodes.getLength(); iLoop1++) ~~~~{ ~~~~~~~~try ~~~~~~~~{ ~~~~~~~~~~~~strUUID = ""; ~~~~~~~~~~~~strKey = ""; ~~~~~~~~~~~~strValue = ""; ~~~~~~~~~~~~xmlNextNode = xmlNodes.item(iLoop1); ~~~~~~~~~~~~for (var iLoop2 = 0; iLoop2 < xmlNextNode.getLength(); iLoop2++) ~~~~~~~~~~~~{ ~~~~~~~~~~~~~~~~xmlEntryNode = xmlNextNode.item(iLoop2); ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~// IF NODE IS "key" THEN SAVE NAME *AND* ID ~~~~~~~~~~~~~~~~if ( xmlEntryNode.getNodeName() == "key") ~~~~~~~~~~~~~~~~{ ~~~~~~~~~~~~~~~~~~~~// GET NEXT KEY ~~~~~~~~~~~~~~~~~~~~strKey = xmlEntryNode.item(0).getNodeValue(); ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~// GET THE ID FOR THE CURRENT KEY ~~~~~~~~~~~~~~~~~~~~// NEED EQUIVALENT TO: xmlKey = xmlNextNode.parent.parent.child["uuid"]; ~~~~~~~~~~~~~~~~~~~~// PER: http://www.w3schools.com/XPath/xpath_syntax.asp ~~~~~~~~~~~~~~~~~~~~// ..~~~~Selects the parent of the current node ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~// DOESN'T WORK (RETURNS undefined): ~~~~~~~~~~~~~~~~~~~~xmlUuidNode = xmlNextNode.getNodes("../../../uuid"); ~~~~~~~~~~~~~~~~~~~~if ( xmlUuidNode.getLength() > 0) ~~~~~~~~~~~~~~~~~~~~{ ~~~~~~~~~~~~~~~~~~~~~~~~strUUID = xmlUuidNode.item(0).getNodeValue(); ~~~~~~~~~~~~~~~~~~~~} ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~// FOUND A ".parentNode" PROPERTY ON WIKI AT: ~~~~~~~~~~~~~~~~~~~~// http://wiki.servicenow.com/index.php?title=Useful_Task_Scripts ~~~~~~~~~~~~~~~~~~~~// but doesn't seem to apply to DOM Node objects ~~~~~~~~~~~~~~~~~~~~// this code blows up the freeform script tool: ~~~~~~~~~~~~~~~~~~~~//xmlUuidNode = xmlEntryNode.parentNode; ~~~~~~~~~~~~~~~~} ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~// IF NODE IS "value" SAVE VALUE ~~~~~~~~~~~~~~~~if ( xmlEntryNode.getNodeName() == "value") ~~~~~~~~~~~~~~~~{ ~~~~~~~~~~~~~~~~~~~~// GET NEXT VALUE ~~~~~~~~~~~~~~~~~~~~strValue = xmlEntryNode.item(0).getNodeValue(); ~~~~~~~~~~~~~~~~} ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~// IF HAVE UUID & NAME THEN INCLUDE IN OUTPUT ~~~~~~~~~~~~~~~~if ( (strUUID.length > 0) && (strName.length > 0) ) ~~~~~~~~~~~~~~~~{ ~~~~~~~~~~~~~~~~~~~~strResult += "" + ~~~~~~~~~~~~~~~~~~~~~~~~"UUID=\"" + strUUID + "\", " + ~~~~~~~~~~~~~~~~~~~~~~~~"key=\"" + strKey + "\", " +
file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java 3/8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

~~~~~~~~~~~~~~~~~~~~~~~~"value=\"" + strValue + "\"\n"; ~~~~~~~~~~~~~~~~} ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~} // for (var iLoop2 ~~~~~~~~} // try ~~~~~~~~catch (e) ~~~~~~~~{ ~~~~~~~~~~~~strErrors += "Error in item #" + iLoop1.toString() + ": " + e.message + "\n"; ~~~~~~~~~~~~iErrorCount++; ~~~~~~~~} ~~~~} // for (var iLoop1 ~~~~ ~~~~// SHOW MESSAGE IF NONE FOUND ~~~~if (strResult.length == 0) ~~~~{ ~~~~~~~~strResult = "(NONE FOUND.)\n"; ~~~~} ~~~~ ~~~~// SHOW ERRORS ~~~~if (iErrorCount > 0) ~~~~{ ~~~~~~~~strErrors = iErrorCount.toString() + " ERRORS:\n" + strErrors; ~~~~} ~~~~else ~~~~{ ~~~~~~~~strErrors = "(NO ERRORS.)\n"; ~~~~} ~~~~ ~~~~// DISPLAY RESULTS ~~~~gs.log("\nRESULTS OF testXPath:\n" + strErrors + strResult, "testXPath"); ~~~~ ~~~~// TEXT XML ~~~~this.get_XML_String = function() ~~~~{ ~~~~~~~~var myString = ""; ~~~~~~~~myString += "<?xml version=\"1.0\" encoding=\"windows-1252\" standalone=\"true\"?>\n"; ~~~~~~~~myString += "<deviceManagementWebServiceResponse>\n"; ~~~~~~~~myString += "~~~~<devices>\n"; ~~~~~~~~myString += "~~~~~~~~<device id=\"1\">\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<uuid>uuid1</uuid>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<principal>principal1</principal>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<blockReason>blockreason1</blockReason>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<clientId>clientid1</clientId>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<details>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field1</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>1</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field2</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>2</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field3</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value></value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~</details>\n"; ~~~~~~~~myString += "~~~~~~~~</device>\n"; ~~~~~~~~myString += "~~~~~~~~<device id=\"2\">\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<uuid>uuid2</uuid>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<principal/>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<blockReason>blockreason2</blockReason>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<clientId>clientId2</clientId>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<details>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n";
file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java 4/8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field 1</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>4</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field 2</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>5</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field 3</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>6</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~</details>\n"; ~~~~~~~~myString += "~~~~~~~~</device>\n"; ~~~~~~~~myString += "~~~~~~~~<device id=\"3\">\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<uuid>uuid3</uuid>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<principal>principal3</principal>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<blockReason>blockreason3</blockReason>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<clientId>clientid3</clientId>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<details>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field1</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>7</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field2</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value></value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field 3</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>9</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~</details>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<countryCode>3</countryCode>\n"; ~~~~~~~~myString += "~~~~~~~~</device>\n"; ~~~~~~~~myString += "~~~~~~~~<device id=\"4\">\n"; ~~~~~~~~myString += "~~~~~~~~~~~~<details>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field1</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>10</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~<entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<key>field2</key>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~~~~~<value>11</value>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~~~~~</entry>\n"; ~~~~~~~~myString += "~~~~~~~~~~~~</details>\n"; ~~~~~~~~myString += "~~~~~~~~</device>\n"; ~~~~~~~~myString += " </devices>\n"; ~~~~~~~~myString += "</deviceManagementWebServiceResponse>\n"; ~~~~~~~~return myString; ~~~~}; // this.get_XML_String ~~~~ } // testXPath Support In your example xmlNode1 is a DOM Node object, and it doesn't have toString(). In order to serialize it to string, so that you could pass it to XMLDocument, you would need to write a custom JavaScript method to serialize node to string. If you have not considered already, writing a nested XPATH query could be a option for e.g. var node = xmldoc.getNode("/test/one/two"); Regards,

file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java

5/8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

Support I'm still looking for this information for you. I'll look at the implementation for XMLDocument class, and shall get back to you with more information. Thanks, Support Our team that specializes in scripting is looking into this and will update you with a solution or request for more details. Regards, Developer OK, please let me know, because I am still having trouble scripting with XMLDocument. Is it possible to narrow down an XML document object with an xpath query, then feed the results to a 2nd xpath query, and so on? I have code like this, but it does not seem to be working: xmlDoc1 = new XMLDocument( xmlString ); xmlDoc1 = xmlDoc1.getNode( xpathQueryString1 ); xmlDoc1 = xmlDoc1.getNode( xpathQueryString2 ); etc. I am not sure if my xpath query has errors, or if the object returned by .getNode is a different type that does not itself support .getNode? In that case, I would think that I need to convert the object back into an XMLDocument object, by converting it back to an XML string and instantiating a 2nd XMLDocument, which can then be queried with another xpath: xmlDoc1 = new XMLDocument( xmlString ); xmlNode1 = xmlDoc1.getNode(xpathQueryString1 ); // xmlNode1.getLength() returns 85 xmlDoc2 = new XMLDocument( xmlNode1.toString() ); // try/catch on this line errors out with error message "null" xmlNode2 = xmlDoc2.getNode( xpathQueryString2 ); However, I am having trouble turning xmlNode1 back into an XMLDocument, the toString doesn't seem to work for retrieving the node's raw XML string. How do you retrieve the raw XML for xmlDoc and xmlNode above? Thanks Developer OK, please let me know, because I am still having trouble scripting with XMLDocument. Is it possible to narrow down an XML document object with an xpath query, then feed the results to a 2nd xpath query, and so on? I have code like this, but it does not seem to be working: xmlDoc1 = new XMLDocument( xmlString ); xmlDoc1 = xmlDoc1.getNode( xpathQueryString1 ); xmlDoc1 = xmlDoc1.getNode( xpathQueryString2 ); etc. I am not sure if my xpath query has errors, or if the object returned by .getNode is a different type that does not itself support .getNode?
file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java 6/8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

In that case, I would think that I need to convert the object back into an XMLDocument object, by converting it back to an XML string and instantiating a 2nd XMLDocument, which can then be queried with another xpath: xmlDoc1 = new XMLDocument( xmlString ); xmlNode1 = xmlDoc1.getNode(xpathQueryString1 ); // xmlNode1.getLength() returns 85 xmlDoc2 = new XMLDocument( xmlNode1.toString() ); // try/catch on this line errors out with error message null xmlNode2 = xmlDoc2.getNode( xpathQueryString2 ); However, I am having trouble turning xmlNode1 back into an XMLDocument, the toString doesnt seem to work for retrieving the nodes raw XML string. How do you retrieve the raw XML for xmlDoc and xmlNode above? Thanks Support I am confirming the information that you requested and will update this incident with the details as soon as possible. Regards, Developer Question: I have some questions about the scripting XMLDocument and node objects. I read the XMLDocument documentation in the Service Now wiki and am not finding the information I need. 1. Is the node object returned by the XMLDocument.getNode method documented in the wiki, or is it just another XMLDocument object? If it is a different object type, where are the properties & methods documented? 2. What property or method (if one exists) of XMLDocument returns the XML string? Thanks Deficient Wiki Article: https://wiki.servicenow.com/index.php?title=XMLDocument_Script_Object

Original test code:

file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java

7/8

1/20/14

How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow JavaScript scripting).htm

file:///U:/Programs/ServiceNow/How do you apply xpath query to results from another xpath query + convert DOM Node object to raw XML text (ServiceNow Java

8/8

Vous aimerez peut-être aussi