XPath - 基于以下兄弟选择节点

时间:2011-09-24 18:12:59

标签: xpath qml

我有这样的查询:

/plist/dict[1]/dict/dict/dict/key/following-sibling::dict/string[string()='Algier']

我真正想要选择的是'key'节点(就在follow-sibling :: dict之前)。

xml是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
    <dict>
    <key>en_GB</key>
            <dict>
                <key>Africa</key>
                <dict>
                    <key>Algeria</key>
                    <dict>
                        <key>60390</key>
                        <dict>
                            <key>NAME</key>
                            <string>Algier</string>
                            <key>LATITUDE</key>
                            <string>36.7500</string>
                            <key>LONGITUDE</key>
                            <string>3.0500</string>
                        </dict>
                        <key>60391</key>
                        <dict>
                            <key>NAME</key>
                            <string>Some other city</string>
                            <key>LATITUDE</key>
                            <string>36.7500</string>
                            <key>LONGITUDE</key>
                            <string>3.0500</string>
                        </dict>
                    </dict>
                </dict>
        </dict>
    </dict>
</plist>

换句话说,我想在城市名称为'Algier'时选择'60390'或在城市名称为'其他城市'时选择60391。

我在QML XmlListModel中执行此操作。

更新了代码 使用QML:

import QtQuick 1.0

Rectangle {
    id: container;
    width: 360
    height: 360

    function onLocationModelLoaded(){
        console.debug(weLocationModel.count);
    }

    XmlListModel{
        id: weLocationModel;
        source: "we_locations.plist";
        query: "/*/dict/dict/dict/dict/key[following-sibling::dict[1]/key[.='NAME' and following-sibling::string[1] = 'Algier']]"

        XmlRole{
            name: "cityId";
            query: "name()";
        }
        onStatusChanged: {
            if (status == XmlListModel.Ready){
                console.debug("Location Model Ready");
                container.onLocationModelLoaded();
            }
        }
    }
}

似乎嵌套的跟随兄弟无法正常工作。 例如:

query: "/*/dict/dict/dict/dict/key[following-sibling::dict[1]/key[.='NAME']]"

这两种情况总是会回归:

Error XPST0003 in file:///Users/Ali/qtprojects/welocationtest-build-simulator/welocationtest.app/Contents/MacOS/welocationtest, at line 2, column 97: syntax error, unexpected ], expecting )
Error XPST0003 in file:///Users/Ali/qtprojects/welocationtest-build-simulator/welocationtest.app/Contents/MacOS/welocationtest, at line 2, column 91: syntax error, unexpected ], expecting end of file
file:///Users/Ali/qtprojects/welocationtest-build-simulator/welocationtest.app/Contents/Resources/qml/welocationtest/main.qml:17:9: QML XmlRole: invalid query: "name()"
Location Model Ready
0

QML是否可能不遵循XPath标准?该解决方案适用于所有其他路径编辑器。

2 个答案:

答案 0 :(得分:5)

一个精确选择所需key元素的XPath表达式是

   /*/dict/dict/dict/dict
     /key
        [following-sibling::dict[1]/key
                  [.='NAME'
                 and
                   following-sibling::string[1] = $pCity
                  ]
        ]

当{pmity设置/替换 - "Algier"时,此XPath表达式选择

<key>60390</key>

当{pmity设置/替换 - "Some other city"时,此XPath表达式选择

<key>60391</key>

基于XSLT的验证

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pCity" select="'Some other city'"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "/*/dict/dict/dict/dict
     /key
        [following-sibling::dict[1]/key
                  [.='NAME'
                 and
                   following-sibling::string[1] = $pCity
                  ]
        ]
  "/>
 </xsl:template>
</xsl:stylesheet>

对提供的XML文档应用此转换时

<plist version="1.0">
    <dict>
        <key>en_GB</key>
        <dict>
            <key>Africa</key>
            <dict>
                <key>Algeria</key>
                <dict>
                    <key>60390</key>
                    <dict>
                        <key>NAME</key>
                        <string>Algier</string>
                        <key>LATITUDE</key>
                        <string>36.7500</string>
                        <key>LONGITUDE</key>
                        <string>3.0500</string>
                    </dict>
                    <key>60391</key>
                    <dict>
                        <key>NAME</key>
                        <string>Some other city</string>
                        <key>LATITUDE</key>
                        <string>36.7500</string>
                        <key>LONGITUDE</key>
                        <string>3.0500</string>
                    </dict>
                </dict>
            </dict>
        </dict>
    </dict>
</plist>

产生了想要的正确结果

<key>60391</key>

在上述转换中,我们替换

 <xsl:param name="pCity" select="'Some other city'"/>

<强>与

 <xsl:param name="pCity" select="'Algier'"/>

并再次应用转换,然后我们再次获得正确的结果

<key>60390</key>

答案 1 :(得分:1)

要获取城市的数量,您也可以使用RegEx(特别是如果QML XPath支持不够好):

import QtQuick 1.0

Rectangle {
    id: container

    width: 360
    height: 360

    Component.onCompleted: {
        loadWeLocationsFile();
    }

    property string weLocationsXML
    signal weLocationsLoaded()

    function loadWeLocationsFile() {
        // load file
        var doc = new XMLHttpRequest();
        doc.onreadystatechange = function() {
            if (doc.readyState == XMLHttpRequest.DONE) {
                // get file content
                weLocationsXML = doc.responseText;

                // emit signal
                weLocationsLoaded();
            }
        }

        doc.open("GET", "we_locations.plist");
        doc.send();
    }

    function getIDByName(name) {
        // escape special characters for regex (maybe there is a better way to do this)
        var safeName = name.replace(/[-.,?+*#^$()[\]{}\\|]/g, "\\$&");

        // create regex
        var regex = new RegExp("<key>(.*?)</key>\\s*<dict>\\s*<key>NAME</key>\\s*<string>" + safeName + "</string>", "m");

        // execute regex
        var match = regex.exec(weLocationsXML);

        if (match != null && match.length > 1) {
            return match[1];  // name found, group 1 contains id
        } else {
            return null;  // no such name in XML
        }
    }

    // Test it ...
    onWeLocationsLoaded: {
        console.log("Number for 'Algier':", getIDByName("Algier"));
        console.log("Number for 'NotInXML':", getIDByName("NotInXML"));
        console.log("Number for 'Some other city':", getIDByName("Some other city"));
    }
}

<强>输出:

Number for 'Algier': 60390
Number for 'NotInXML': null
Number for 'Some other city': 60391

如果您需要QML模型中的数字,可以创建ListModel并将数字添加到其中。