Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath - selecting node based on following sibling

Tags:

xpath

qml

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.

like image 906
zakishaheen Avatar asked Feb 14 '26 20:02

zakishaheen


1 Answers

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>
like image 175
Dimitre Novatchev Avatar answered Feb 17 '26 20:02

Dimitre Novatchev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!