Home > front end >  Nested xml - retrieve all itemNos that satisfies condition
Nested xml - retrieve all itemNos that satisfies condition

Time:11-30

I want to return all the itemNos No which satisfies the condition. But my code only returns the first itemNo (whose Detail Id="3") but not the rest.

Below returns only '0001'. How do I make it return both '0001' and '0002', Since both has ID = 3.

XML structure:

<!-- language: lang-xml -->

<xml>
  <Items>

    <Item No="0001">
      <Details>
        <Detail Id="3">
          <Colors>
            <Color colorName="green" />
            <Color colorName="yellow" />
          </Colors>
        </Detail>
      </Details>
    </Item>

    <Item No="0002">
      <Details>
        <Detail Id="3">
          <Colors>
            <Color colorName="purple" />
            <Color colorName="pink" />
          </Colors>
        </Detail>
        <Detail Id="6">
          <Colors>
            <Color colorName="grey" />
            <Color colorName="orange" />
          </Colors>
        </Detail>
      </Details>
    </Item>

    <Item No="0003">
      <Details>
        <Detail Id="8">
          <Colors>
            <Color colorName="red" />
          </Colors>
        </Detail>
      </Details>
    </Item>

  </Items>
</xml>     

const search_id = "3"

const foundNo = []

let ans= xmlDoc.evaluate(`//Item[Details/Detail/@Id="${search_id}"]/@No`, xmlDoc.documentElement);
        const foundNode = ans.iterateNext();
        foundNo = foundNode.textContent // this returns Item No "0001"

How do I make it return both '0001' and '0002'. Returns only "0001" currently. Thank you.

CodePudding user response:

With the browser based XPath API you need to iterate and collect the results:

const xml = `<xml>
  <Items>

    <Item No="0001">
      <Details>
        <Detail Id="3">
          <Colors>
            <Color colorName="green" />
            <Color colorName="yellow" />
          </Colors>
        </Detail>
      </Details>
    </Item>

    <Item No="0002">
      <Details>
        <Detail Id="3">
          <Colors>
            <Color colorName="purple" />
            <Color colorName="pink" />
          </Colors>
        </Detail>
        <Detail Id="6">
          <Colors>
            <Color colorName="grey" />
            <Color colorName="orange" />
          </Colors>
        </Detail>
      </Details>
    </Item>

    <Item No="0003">
      <Details>
        <Detail Id="8">
          <Colors>
            <Color colorName="red" />
          </Colors>
        </Detail>
      </Details>
    </Item>

  </Items>
</xml>`;

const xmlDoc = new DOMParser().parseFromString(xml, 'application/xml');

const search_id = "3";

const foundNos = [];

const ans = xmlDoc.evaluate(`//Item[Details/Detail/@Id="${search_id}"]/@No`, xmlDoc);

var foundNode;
while ((foundNode = ans.iterateNext()) != null)
  foundNos.push(foundNode.textContent);
  
console.log(foundNos);

I would suggest to switch to XPath 3.1 based on SaxonJS where it is all much easier to collect the data with one XPath expression and have it returned as one JS array:

const xml = `<xml>
  <Items>

    <Item No="0001">
      <Details>
        <Detail Id="3">
          <Colors>
            <Color colorName="green" />
            <Color colorName="yellow" />
          </Colors>
        </Detail>
      </Details>
    </Item>

    <Item No="0002">
      <Details>
        <Detail Id="3">
          <Colors>
            <Color colorName="purple" />
            <Color colorName="pink" />
          </Colors>
        </Detail>
        <Detail Id="6">
          <Colors>
            <Color colorName="grey" />
            <Color colorName="orange" />
          </Colors>
        </Detail>
      </Details>
    </Item>

    <Item No="0003">
      <Details>
        <Detail Id="8">
          <Colors>
            <Color colorName="red" />
          </Colors>
        </Detail>
      </Details>
    </Item>

  </Items>
</xml>`;

const xmlDoc = new DOMParser().parseFromString(xml, 'application/xml');

const search_id = 3;

const foundNos = SaxonJS.XPath.evaluate(`//Item[Details/Detail/@Id = $search_id]/@No/string()`, xmlDoc, { params : { search_id : search_id } });

console.log(foundNos);
<script src="https://martin-honnen.github.io/Saxon-JS-2.5/SaxonJS2.js"></script>

SaxonJS is a product from Saxonica, you can download it here and read its documentation here.

  • Related