XPath - 根据以下同级选择节点

发布于 2024-12-06 08:00:40 字数 3335 浏览 1 评论 0原文

我有一个这样的查询:

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

我真正想要选择的是“关键”节点(就在以下同级::字典之前)。

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>

换句话说,当城市名称是“阿尔及尔”时,我想选择“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();
            }
        }
    }
}

似乎嵌套的 following-sibling 不起作用。 例如:

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 标准吗?该解决方案适用于所有其他路径编辑器。

I have a query like this:

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

What I really want to select is the 'key' node (just before the following-sibling::dict) one.

The xml is like this :

<?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>

In other words, I want to select '60390' when the city name is 'Algier' or (60391 when city name is 'some other city').

I'm doing this in a QML XmlListModel.

Updated code
QML used:

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();
            }
        }
    }
}

It seems like the nested following-sibling is not working.
for example something like:

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

Both of these always return:

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

Could it be possible QML is not following XPath standard? THe solution works in all other path editors.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

只为一人 2024-12-13 08:00:40

精确选择所需 key 元素的 XPath 表达式如下

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

当 $pCity 设置/替换为 "Algier" 时,此 XPath 表达式选择

<key>60390</key>

当 $pCity 设置/替换为 “其他城市” 时,此 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>

One XPath expression that selects exactly the wanted key element is this:

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

When $pCity is set/substituted-by "Algier", this XPath expression selects:

<key>60390</key>

When $pCity is set/substituted-by "Some other city", this XPath expression selects:

<key>60391</key>

XSLT-based verification:

<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>

When this transformation is applied against the provided XML document:

<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>

the wanted, correct result is produced:

<key>60391</key>

When in the above transformation we replace:

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

with:

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

and apply the transformation again, then again we get the correct result:

<key>60390</key>
叹倦 2024-12-13 08:00:40

要获取城市的号码,您也可以使用正则表达式(特别是在 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, "\\
amp;");

        // 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 并向其中添加数字。

To get the number for a city you can use a RegEx, too (especially if QML XPath support is not good enough):

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, "\\
amp;");

        // 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"));
    }
}

Output:

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

If you need the number in a QML model you can create a ListModel and add the number to it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文