简体   繁体   中英

How to find the node position of a value in an XML tree?

Based on a value I input on the page, I want to retrieve the relevant XML data.

For example, if I input/select option "Michigan" from the datalist input field on my page, I want to find the node position of Michigan in the XML document. By knowing the node position, I can retrieve other information from the XML document corresponding to Michigan such as GDP and POPULATION .

I know I should change [1] to a variable such as [i] , but how should I code the function?

 var n = document.getElementById("myInputId"); n.addEventListener("keyup", function(event) { event.preventDefault(); if (event.keyCode === 13) { document.getElementById("myButton").click(); } }); function loadXMLDoc() { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { myFunction(xmlhttp); } }; xmlhttp.open("GET", "state_data.xml", true); xmlhttp.send(); } function myFunction(xml) { var x, i, xmlDoc; xmlDoc = xml.responseXML; x = xmlDoc.getElementsByTagName("UNIT") var s = xmlDoc.getElementsByTagName("STATE")[1].childNodes[0].nodeValue; document.getElementById("state").innerHTML = s; var gElem = xmlDoc.getElementsByTagName("GDP"); var g = (gElem.length > 0) ? gElem[1].childNodes[0].nodeValue : ""; document.getElementById("gdp").innerHTML = g; var pElem = xmlDoc.getElementsByTagName("POPULATION"); var p = (pElem.length > 0) ? pElem[1].childNodes[0].nodeValue : ""; document.getElementById("population").innerHTML = p; var a = n.value document.getElementById("inputValue").innerHTML = a; xmlDoc.UNITs.forEach(function(e, z) { var q = document.getElementById("inputValue").innerHTML; if (e.properties.id == q) { document.getElementById("nodePosition").innerHTML = z; } }); } 
 <body onload="loadXMLDoc()"> <input list="myInput" id="myInputId" value=""> <button id="myButton" onClick="loadXMLDoc()">submit</button> <p>input value: <span id="inputValue"></span></p> <p>XML tree node position of input value: <span id="nodePosition"></span></p> <p>State: <span id="state"></span></p> <p>GDP: <span id="gdp"></span></p> <p>Population: <span id="population"></span></p> <datalist id="myInput"> <option id="AL">Alabama</option> <option id="CA">California</option> <option id="MI">Michigan</option> <option id="TX">Texas</option> <option id="WI">Wisconsin</option> </datalist> 

Here's my XML:

<?xml version="1.0" encoding="UTF-8"?>
<STATE_DATA>
 <UNIT>
    <STATE>Wisconsin</STATE>
    <GDP>232,300,000,000</GDP>
    <POPULATION>5,800,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>Alabama</STATE>
    <GDP>165,800,000,000</GDP>
    <POPULATION>4,900,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>California</STATE>   
    <!-- Note: the GDP node for this unit is missing -->
    <POPULATION>39,600,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>Texas</STATE>
    <GDP>1,600,000,000,000</GDP>
    <POPULATION>28,300,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>Michigan</STATE>
    <GDP>382,000,000</GDP>
    <POPULATION>10,000,000</POPULATION>
 </UNIT>
</STATE_DATA>

Things are simplified somewhat if you resort to the xml handling functionality that comes with modern browsers. The rewrite centers around XPath expressions. A complete intro is beyond the scope of this answer, but in a nutshell it's a pattern language to retrieve content from an xml tree.

The xpath expressions are used to extract the relevant elements from the xml file.

The solution does not require any prior modifications to the xml ( contrary to the prior revision of this solution ).

The code sample is standalone - just save it as a local html file or serve it from a http server. To make it work, the xml data is stored in a script element serving as a data island.

Changing that design back to fetching the xml data with an ajax call should be straightforward..

Consider the code a proof of concept presenting the structure of an xpath-based approach.

<!DOCTYPE html>
<!--
    SO
    datalist / xml handling
    Q 51200490 (https://stackoverflow.com/questions/51200490/how-to-find-the-node-position-of-a-value-in-an-xml-tree/51201494)
    A 
-->
<html>
    <head>
        <title>SO sample</title>
        <script>
 // Setup of keypress event handler, default selection of xml data.
 function setupEH () {
    var n = document.getElementById("myInputId");
    n.addEventListener("keyup", function(event) {
        event.preventDefault();
        if (event.keyCode === 13) {
            document.getElementById("myButton").click();
        }
    });

    loadXMLDoc('Alabama'); // comment out this line if you want a vanilla UI after loading the html page.
}

// Load the xml document
function loadXMLDoc( statelabel ) {
    // The xml document is retrieved with the following steps:
    //      1. Obtain the (in-document) source as a DOM node.
    //      2. Extract textual content.
    //      3. Instantiate the xml parser (a browser built-in)
    //      4. Parse textual content into an xml document
    //
    //  When retrieving the xml document by means of ajax, these steps will be handled by the library for you - a parsed xml document will be available as a property or through calling a method.
    //
    let x_xmlisland = document.getElementById("template_xml");
    let s_xmlsource = x_xmlisland.textContent; 
    let parser = new DOMParser();
    let xmlDoc = parser.parseFromString(s_xmlsource, "application/xml");

    myFunction(xmlDoc, statelabel); // Actual work ...
}

// Processing the xml document 
function myFunction(xmlDoc, statelabel) {
    //    debugger; // uncomment to trace

    //
    //  Every bit of information is processed as follows:
    //      - Get the relevant xml subtree ( `UNIT` element of the selected state incl.descendants )
    //      - Extract the textual value.
    //      - Feed the textual value to the Html elements prsenting the result.
    //
    var xpr_current_unit  = xmlDoc.evaluate("/STATE_DATA/UNIT[./STATE[./text() = '"+statelabel+"']]",xmlDoc,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
    var node_current_unit = xpr_current_unit.iterateNext();

    //
    //  The subsequent calls to xmlDoc.evaluate set the current UNIT element as their context node ('starting point'/'temporary root' for the xpath expression).
    //  The context node is referenced by '.' (dot) 
    //
    var xpr_s   = xmlDoc.evaluate("./STATE/text()",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
    var node_s  = xpr_s.iterateNext();
    var s       = node_s.textContent
    document.getElementById("state").innerHTML = s;

    var xpr_g   = xmlDoc.evaluate("./GDP/text()",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
    var node_g  = xpr_g.iterateNext();
    var g = "Unknown";
    if ( node_g !== null ) {
        g = node_g.textContent;
    }
    document.getElementById("gdp").innerHTML = g;

    var xpr_p   = xmlDoc.evaluate("./POPULATION/text()",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
    var node_p  = xpr_p.iterateNext();
    var p = "Unknown";
    if ( node_p !== null ) {
        p = node_p.textContent;
    }
    document.getElementById("population").innerHTML = p;

    // cf. https://stackoverflow.com/a/3437009
    var xpr_u  = xmlDoc.evaluate("count(./preceding::UNIT)+1.",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
    var n_ucount = xpr_u.numberValue;

    document.getElementById("inputValue").innerHTML = s;
    document.getElementById("nodePosition").innerHTML = n_ucount;
}

// Setup the submit click handler
function ehClick ( ) {
    let node_choice     = document.getElementById('myInputId');
    loadXMLDoc(node_choice.value);
}
        </script>
        <style>
        </style>
    </head>
    <body onload="setupEH()">
        <script id="template_xml" type="text/xml"><?xml version="1.0" encoding="UTF-8"?>
<STATE_DATA>
 <UNIT>
    <STATE>Wisconsin</STATE>
    <GDP>232,300,000,000</GDP>
    <POPULATION>5,800,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>Alabama</STATE>
    <GDP>165,800,000,000</GDP>
    <POPULATION>4,900,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>California</STATE>   
    <!-- Note: the GDP node for this unit is missing -->
    <POPULATION>39,600,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>Texas</STATE>
    <GDP>1,600,000,000,000</GDP>
    <POPULATION>28,300,000</POPULATION>
 </UNIT>
 <UNIT>
    <STATE>Michigan</STATE>
    <GDP>382,000,000</GDP>
    <POPULATION>10,000,000</POPULATION>
 </UNIT>
</STATE_DATA>
        </script>
        <input list="myInput" id="myInputId" value="">
        <button id="myButton" onClick="ehClick()">submit</button>

        <p>input value: <span id="inputValue"></span></p>
        <p>XML tree node position of input value: <span id="nodePosition"></span></p>
        <p>State: <span id="state"></span></p>
        <p>GDP: <span id="gdp"></span></p>
        <p>Population: <span id="population"></span></p>

        <datalist id="myInput">
        <option id="AL">Alabama</option>
        <option id="CA">California</option>
        <option id="MI">Michigan</option>
        <option id="TX">Texas</option>
        <option id="WI">Wisconsin</option>
        </datalist>
    </body>
</html>

References

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM