Xpath using Javascript shows Missing semicolon error

Team / @Dino / @Mathanprasath k

My project requirement is to use JS to extract an element using XPath. I'm not able to retrive the value of an element(StandardId) with the below sample XML request and XPath notation using JavaScript Policy.

Please help !

XML Payload

<Workers xmlns="http://ctsi.asee.com/hr" xmlns:cmn="http://ctsi.asee.com/common" xmlns:hrrec="http://ctsi.asee.com/hr/testing" xmlns:hrben="http://ctsi.asee.com/hr/benefits">
  <cmn:Link href="https://ctrbs-ist.ctmasee.net:5001/hr/v8/workers?data.page=1&contact-info.work-email=suresh.varthi%40ctmasee.com&data.page-size=10" rel="self"/>
  <Worker>
    <cmn:Link href="https://ctrbs-ist.ctmasee.net:5004/hr/v8/workers/J1547583" rel="self"/>
    <cmn:StandardId>12345</cmn:StandardId>    
  </Worker>
</Workers>

XPath

var payload = response.content.asXML;


var ns1 = new Namespace('http://ctsi.asee.com/hr'); 
var ns2 = new Namespace('http://ctsi.asee.com/common');


var sId= payload.ns1::Workers.Worker.ns2::StandardId.toString();
Solved Solved
1 3 861
1 ACCEPTED SOLUTION

There are a couple problems.

1. Escaping

First, Dane is correct in the comment - a valid XML document must escape ampersand characters, even when contained within a quote-delimited attribute value. For reference: https://www.w3.org/TR/xml/#syntax

[Definition: Markup takes the form of start-tags, end-tags, empty-element tags, entity references, character references, comments, CDATA section delimiters, document type declarations, processing instructions, XML declarations, text declarations, and any white space that is at the top level of the document entity (that is, outside the document element and not inside any other markup).]

[Definition: All text that is not markup constitutes the character data of the document.]

The ampersand character (&) and the left angle bracket (<) must not appear in their literal form, except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section. If they are needed elsewhere, they must be escaped using either numeric character references or the strings " & " and " < " respectively.

It occurs to me that it's possible that your XML is actually correct, and it is the forum software that is substituting an unescaped & for the & amp ; . If that's the case, ignore this point.

2. XPath

Second: your selection string - your xpath - isn't right. It needs one less link, and needs another ns1. After fixing the XML escaping, this works for me:

var message = context.getVariable(properties.sourceMessage);
if (message && message.content){
  var xmlobj = new XML(message.content); // in lieu of .asXML
  if (xmlobj.name().localName === 'Workers') {
    var workers = xmlobj;
    var hr = new Namespace('http://ctsi.asee.com/hr');
    var cmn = new Namespace('http://ctsi.asee.com/common');
    var sIdtext = workers.hr::Worker.cmn::StandardId.text();
    context.setVariable('extraction_result', 'success');
    context.setVariable('extracted_value', sIdtext);
  }
  else {
    context.setVariable('extraction_result', 'unrecognized root element');
  }
}
else {
  context.setVariable('extraction_result', 'no message');
}

Notice that the path is workers.hr::Worker.cmn::StandardId.text();

The root xmlobj is pointing at the workers element. In your code, where you have

payload.ns1::Workers

...you are trying to find a child of the root element with element name "Workers". But the root element is actually "Workers". So that's not necessary.

BTW, my JS code above, referencing the properties.sourceMessage , assumes this kind of config for the JS policy:

<Javascript name='JS-ExtractValue' timeLimit='600' >
  <Properties>
    <Property name='sourceMessage'>response</Property>
  </Properties>
  <ResourceURL>jsc://extractValue.js</ResourceURL>
</Javascript>

View solution in original post

3 REPLIES 3

Hi there

What exactly is the error message you're getting? Is this during xml parsing?

Why does the XML payload provided not include escaped &'s ?

If the error you're seeing is

The reference to entity "contact-info.work-email" must end with the ';'

This is due to the &'s not escaped in the xml in the href attribute value ie &

There are a couple problems.

1. Escaping

First, Dane is correct in the comment - a valid XML document must escape ampersand characters, even when contained within a quote-delimited attribute value. For reference: https://www.w3.org/TR/xml/#syntax

[Definition: Markup takes the form of start-tags, end-tags, empty-element tags, entity references, character references, comments, CDATA section delimiters, document type declarations, processing instructions, XML declarations, text declarations, and any white space that is at the top level of the document entity (that is, outside the document element and not inside any other markup).]

[Definition: All text that is not markup constitutes the character data of the document.]

The ampersand character (&) and the left angle bracket (<) must not appear in their literal form, except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section. If they are needed elsewhere, they must be escaped using either numeric character references or the strings " & " and " < " respectively.

It occurs to me that it's possible that your XML is actually correct, and it is the forum software that is substituting an unescaped & for the & amp ; . If that's the case, ignore this point.

2. XPath

Second: your selection string - your xpath - isn't right. It needs one less link, and needs another ns1. After fixing the XML escaping, this works for me:

var message = context.getVariable(properties.sourceMessage);
if (message && message.content){
  var xmlobj = new XML(message.content); // in lieu of .asXML
  if (xmlobj.name().localName === 'Workers') {
    var workers = xmlobj;
    var hr = new Namespace('http://ctsi.asee.com/hr');
    var cmn = new Namespace('http://ctsi.asee.com/common');
    var sIdtext = workers.hr::Worker.cmn::StandardId.text();
    context.setVariable('extraction_result', 'success');
    context.setVariable('extracted_value', sIdtext);
  }
  else {
    context.setVariable('extraction_result', 'unrecognized root element');
  }
}
else {
  context.setVariable('extraction_result', 'no message');
}

Notice that the path is workers.hr::Worker.cmn::StandardId.text();

The root xmlobj is pointing at the workers element. In your code, where you have

payload.ns1::Workers

...you are trying to find a child of the root element with element name "Workers". But the root element is actually "Workers". So that's not necessary.

BTW, my JS code above, referencing the properties.sourceMessage , assumes this kind of config for the JS policy:

<Javascript name='JS-ExtractValue' timeLimit='600' >
  <Properties>
    <Property name='sourceMessage'>response</Property>
  </Properties>
  <ResourceURL>jsc://extractValue.js</ResourceURL>
</Javascript>