Get list of XPaths of elements [duplicate]

2019-03-02 10:49发布

问题:

This question already has an answer here:

  • Generate/get xpath from XML node java 8 answers

I have NodeList of elements with specific name and I would like to have XPath of all of theese nodes.

I cannot find a way how to do that.

NodeList nList = doc.getElementsByTagName("definition");
 for (int i = 0; i < nList.getLength(); i++) {
 Node node = nList.item(i);
 System.out.println(node.GET_XPATH());
}

I'm looking for a method like GET_XPATH()

Do someone know how to do that? Or is it even possible?

If it is possible with XSLT can use it as well, but prefer if someone know about this possibility in Java.

REASON: I need a set of pointers to XML library. Pointers to definition elements.

EXAMPLE Input:

<odML>
    <section>
        <type>experiment</type>
        <name>Experiment</name>
        <definition></definition>
        <property>
            <definition></definition>
        </property>
        <property>
            <definition></definition>
            <value>
                <definition></definition>
            </value>
        </property>
    </section>
    <definition></definition>
</odML>

Output:

/odML/section/definition

/odML/section/property[1]/definition

/odML/section/property[2]/definition

/odML/section/property[2]/value/definition

/odML/definition

回答1:

The following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/"> 
    <xsl:for-each select="//definition">
        <xsl:for-each select="ancestor::*">
            <xsl:text>/</xsl:text>
            <xsl:value-of select="name()"/>
            <xsl:if test="(preceding-sibling::*|following-sibling::*)[name()=name(current())]">
                <xsl:text>[</xsl:text>  
                <xsl:value-of select="count(preceding-sibling::*[name()=name(current())]) + 1"/>
                <xsl:text>]</xsl:text>  
            </xsl:if>
        </xsl:for-each>
        <xsl:text>/definition</xsl:text>    
        <xsl:if test="position()!=last()">
            <xsl:text>&#10;</xsl:text>  
        </xsl:if>
    </xsl:for-each>
</xsl:template>  

</xsl:stylesheet>

when applied to your example input, will return:

/odML/section/definition
/odML/section/property[1]/definition
/odML/section/property[2]/definition
/odML/section/property[2]/value/definition
/odML/definition


回答2:

This transformation:

<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="definition">
     <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
     <xsl:text>&#xA;</xsl:text>
  </xsl:template>

  <xsl:template match="*" mode="path">
    <xsl:value-of select="concat('/',name())"/>
    <xsl:if test="../*[name()=name(current())][2]">
        <xsl:value-of select=
        "concat('[',count(preceding-sibling::*[name()=name(current())])+1,']')"/>
    </xsl:if>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>

When applied on the provided source XML document:

<odML>
    <section>
        <type>experiment</type>
        <name>Experiment</name>
        <definition></definition>
        <property>
            <definition></definition>
        </property>
        <property>
            <definition></definition>
            <value>
                <definition></definition>
            </value>
        </property>
    </section>
    <definition></definition>
</odML>

produces the wanted, correct result:

/odML/section/definition
/odML/section/property[1]/definition
/odML/section/property[2]/definition
/odML/section/property[2]/value/definition
/odML/definition