且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在 XML 树中找到值的节点位置?

更新时间:2023-11-25 23:44:16

如果您求助于现代浏览器附带的 xml 处理功能,事情会得到一些简化.重写以 XPath 表达式为中心.完整的介绍超出了这个答案的范围,但简而言之,它是一种从 xml 树中检索内容的模式语言.

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.

xpath 表达式用于从 xml 文件中提取相关元素.

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

该解决方案不需要对 xml 进行任何事先修改(与此解决方案的先前修订相反).

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

代码示例是独立的 - 只需将其保存为本地 html 文件或从 http 服务器提供.为了使其工作,xml 数据存储在作为数据岛的脚本元素中.

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.

将该设计改回使用 ajax 调用获取 xml 数据应该很简单..

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

将代码视为概念证明,展示了基于 xpath 的方法的结构.

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

<!DOCTYPE html>
<!--
    SO
    datalist / xml handling
    Q 51200490 (https://***.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://***.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>

参考资料

  • XPath Programming (Document.evaluate) on MDN
  • Getting alternative values from html datalists
  • Determining xml element position with XPath