Search code examples
xpathantxmltask

XMLPath from ant using XMLTasks can't match if XML file has elements in different name spaces


I'm trying to get some matching using XMLTasks to replace some values in a xml file but it keeps failing due to no match. Using other tools it says that my xpath is correct but I can't figure out what's wrong.

Here the file I'm searching:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
    <type>org.netbeans.modules.apisupport.project</type>
    <configuration>
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
            <code-name-base>simple.server.extension.cardgame</code-name-base>
            <suite-component/>
            <module-dependencies>
                <dependency>
                    <code-name-base>marauroa.lib</code-name-base>
                    <build-prerequisite/>
                    <compile-dependency/>
                    <run-dependency>
                        <release-version>3</release-version>
                        <specification-version>8</specification-version>
                    </run-dependency>
                </dependency>
                <dependency>
                    <code-name-base>simple.server.lib</code-name-base>
                    <build-prerequisite/>
                    <compile-dependency/>
                    <run-dependency>
                        <release-version>0-1</release-version>
                        <specification-version>0.2</specification-version>
                    </run-dependency>
                </dependency>
            </module-dependencies>
            <public-packages>
                <package>dreamer.card.game</package>
                <package>dreamer.card.game.model.events</package>
                <package>dreamer.card.game.price</package>
                <package>dreamer.card.game.storage</package>
                <package>simple.server.extension</package>
                <package>simple.server.extension.card</package>
            </public-packages>
            <class-path-extension>
                <runtime-relative-path>ext/extension/x.jar</runtime-relative-path>
                <binary-origin>../../Simple Marauroa Java/Card Game Extension/dist/x.jar</binary-origin>
            </class-path-extension>
            <class-path-extension>
                <runtime-relative-path>ext/extension/y.jar</runtime-relative-path>
                <binary-origin>../../Simple Marauroa Java/Card Game interface/dist/y.jar</binary-origin>
            </class-path-extension>
        </data>
    </configuration>
</project>

And this is the path expression I'm using:

/project/configuration/data/class-path-extension[1]/runtime-relative-path/text()

Here are the relevant parts of the task I'm trying to run:

<target name="s" depends="-define-xmltasks">
        <propertyselector property="subprojects" match="original.project.dir(.*)" select="\1"/>
        <for list="${subprojects}" param="subproject">
            <sequential>
                <xmltask source="nbproject/project.xml" dest="nbproject/project.xml" failWithoutMatch="true">
                    <replace path="/project/configuration/data/class-path-extension[@{subproject}]/runtime-relative-path/text()" 
                             withText="ext/extension/${extension-lib@{subproject}.dist.jar}"/>
                    <replace path="/project/configuration/data/class-path-extension[@{subproject}]/binary-origin/text()" 
                             withText="${original.project.dir@{subproject}}/dist/${extension-lib@{subproject}.dist.jar}"/>
                </xmltask>
            </sequential>
        </for>
    </target>

@{subproject} resolves to a number and already tried changing it for a number but has the same effect. Any idea?


Solution

  • And this is the path expression I'm using:

    /project/configuration/data/class-path-extension[1]/runtime-relative-path/text()
    

    One way to deal with unprefixed names that are in a non-empty (default) namespace, is to specify the name as a predicate.

    Here is an XPath expression written in this style that selects the wanted node(s):

       /*[name()='project']
         /*[name()='configuration']
           /*[name()='data']
             /*[name()='class-path-extension'][1]
               /*[name()='runtime-relative-path']
                 /text()
    

    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:template match="/">
      <xsl:copy-of select=
      "/*[name()='project']
         /*[name()='configuration']
           /*[name()='data']
             /*[name()='class-path-extension'][1]
               /*[name()='runtime-relative-path']
                 /text()
      "/>
     </xsl:template>
    </xsl:stylesheet>
    

    When this transformation is applied on the provided XML document:

    <project xmlns="http://www.netbeans.org/ns/project/1">
        <type>org.netbeans.modules.apisupport.project</type>
        <configuration>
            <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
                <code-name-base>simple.server.extension.cardgame</code-name-base>
                <suite-component/>
                <module-dependencies>
                    <dependency>
                        <code-name-base>marauroa.lib</code-name-base>
                        <build-prerequisite/>
                        <compile-dependency/>
                        <run-dependency>
                            <release-version>3</release-version>
                            <specification-version>8</specification-version>
                        </run-dependency>
                    </dependency>
                    <dependency>
                        <code-name-base>simple.server.lib</code-name-base>
                        <build-prerequisite/>
                        <compile-dependency/>
                        <run-dependency>
                            <release-version>0-1</release-version>
                            <specification-version>0.2</specification-version>
                        </run-dependency>
                    </dependency>
                </module-dependencies>
                <public-packages>
                    <package>dreamer.card.game</package>
                    <package>dreamer.card.game.model.events</package>
                    <package>dreamer.card.game.price</package>
                    <package>dreamer.card.game.storage</package>
                    <package>simple.server.extension</package>
                    <package>simple.server.extension.card</package>
                </public-packages>
                <class-path-extension>
                    <runtime-relative-path>ext/extension/x.jar</runtime-relative-path>
                    <binary-origin>../../Simple Marauroa Java/Card Game Extension/dist/x.jar</binary-origin>
                </class-path-extension>
                <class-path-extension>
                    <runtime-relative-path>ext/extension/y.jar</runtime-relative-path>
                    <binary-origin>../../Simple Marauroa Java/Card Game interface/dist/y.jar</binary-origin>
                </class-path-extension>
            </data>
        </configuration>
    </project>
    

    the XPath expression is evaluated and the selected node is copied to the output:

    ext/extension/x.jar
    

    Note: For incremental building and verification of XPath expressions you can use a tool such as the XPath visualizer. This tool has helped many thousands of people learn XPath the fun way.