XMLDocument - parse node-element with same name

conmic
Mega Guru

So I am currently playing around with the ECC queue to grab an handle the input XML payload in case of an error on an executed Powershell script.

I am running into an issue where the XML node "error" appears twice in the result. So it makes grabbing the second "error" node with the XMLDocument function "getNodeText()" particularly hard, as such function only takes the first occurrence.

Is anyone experiencing the same issue?

Or can somebody please help me to grab the second, not empty "error" node? Somehow I cannot find the proper way to iterate through the nodes and grab the not empty one. My skills in XML, XPATH and XMLDocument are really limited and I'm somehow not getting any more knowledgeable about it.

ECC_Capture.PNG

Thank you a lot

Kind regards,

Michel

1 ACCEPTED SOLUTION

Another option that seem to work is to use getTextContent() on the node element like this:



var nodeValue = nodes.item(i).getTextContent();


View solution in original post

5 REPLIES 5

Slava Savitsky
Giga Sage

Hi Michel,



One way is to grab all children of the "result" node and loop through them like this:



var nodes = xmldoc.getNodes("//result/*");



for (i = 0; i < nodes.length; i++) {


      gs.log(nodes.item(i).getNodeValue());


}



Assuming the error message is always in the second "error" node, you could take a simpler route and access the last child node under "result" directly:



var nodes = xmldoc.getNode("//result");


var errorText = nodes.getLastChild().getNodeValue();



For more examples, refer to the product documentation:


XMLDocument Script Object - ServiceNow Wiki



For help on XPath syntax, have a look at the following tutorial:


XPath Syntax



Let me know if you have further questions.



Regards,


Slava


Hello Slava,



Thank you for the reply.



My goal is to iterate through each "error" node and group the content together. This is then returned as one error message, just in case there are multiple with content. I have now tested your method and I got a strange behavior that I have already observed before, with the function getNodeValue() always returning 'null'.



I am using the following function in my script include:



_getResponseErrorValue: function(xmldoc) {


  var elements = ""; //debug


  var error = null;


  var nodes = xmldoc.getNodes("//results/result/*");


  for (i = 0; i < nodes.length; i++) {


            if(nodes.item(i).getNodeName() == "error"){


                      var nodeName = nodes.item(i).getNodeName();


                      var nodeValue = nodes.item(i).getNodeValue();


                      //START debug


                      if(i != 0)


                      elements += "\n\n";


                      elements += "Name: " + nodeName + "\n";


                      elements += "Value:\n" + nodeValue;


                      //END debug


                      if(nodeValue != null && nodeValue != ""){


                                error = nodeValue;


                      }


          }


  }


  gs.log(elements, "Script Include: ShellProbe"); //OUTPUT debug


  return error;


},



In the log the debug is well returning my two nodes with the name "error", but the actual value is 'null':


Error_Capture.png



While the initial "simple" script in that function is working well if using "getNodeText", but only in case if there is only one "error" node. It's also working well for the function that handles the "output" node:



_getResponseErrorValue: function(xmldoc) {


  var error = xmldoc.getNodeText("//results/result/error");


  return error;


},



_getResponseOutputValue: function(xmldoc) {


  var output = xmldoc.getNodeText("//results/result/output");


  return output;


}



Any idea why I get this strange behavior? Is it a bug in the "getNodeValue()" function or am I mistaken somewhere?



Kind regards,


Michel Conter


The Name can be retrieved from the node element itself but the Value comes from the text element underneath it. Try this instead:



var nodeName = nodes.item(i).getNodeName();


var nodeValue = nodes.item(i).getLastChild().getNodeValue();


Another option that seem to work is to use getTextContent() on the node element like this:



var nodeValue = nodes.item(i).getTextContent();