从XML节点java生成/获取xpath

从XML节点java生成/获取xpath,java,xml,xslt,xpath,Java,Xml,Xslt,Xpath,我对建议/伪代码/解释感兴趣,而不是实际的实现 我想浏览一下xml文档及其所有节点 检查节点是否存在属性 如果节点没有属性,get/generate字符串及其xpath值 如果节点确实有属性,则迭代属性列表并为每个属性(包括节点)创建xpath 忠告?希望你能提供一些有用的情报 编辑: 这样做的原因是。。我正在用jmeter编写自动测试,所以对于每个请求,我都需要验证请求是否确实完成了它的工作,所以我通过使用xpath获取节点值来断言结果 当请求很小时,手工创建资产并不是问题,但对于较大的资

我对建议/伪代码/解释感兴趣,而不是实际的实现

  • 我想浏览一下xml文档及其所有节点
  • 检查节点是否存在属性
如果节点没有属性,
get/generate字符串及其xpath值
如果节点确实有属性,则迭代属性列表并为每个属性(包括节点)创建xpath

忠告?希望你能提供一些有用的情报

编辑:

这样做的原因是。。我正在用jmeter编写自动测试,所以对于每个请求,我都需要验证请求是否确实完成了它的工作,所以我通过使用xpath获取节点值来断言结果

当请求很小时,手工创建资产并不是问题,但对于较大的资产来说,这确实是一件痛苦的事情。。(额外信息-不相关)

赏金:

我正在寻找java方法

目标

我的目标是通过此ex xml文件实现以下目标:

<root>
    <elemA>one</elemA>
    <elemA attribute1='first' attribute2='second'>two</elemA>
    <elemB>three</elemB>
    <elemA>four</elemA>
    <elemC>
        <elemB>five</elemB>
    </elemC>
</root>
解释:

  • 如果节点值/文本不是null/zero,则获取xpath,添加='nodevalue'以用于断言
  • 如果节点具有属性,则也为其创建断言
赏金更新:

我发现这个例子,它不能产生正确的结果,但我看起来像这样:

  • 使用w3c.dom
  • 递归下降
  • 对于每个节点,都有一种获取xpath的简单方法:将其存储为array/list while#2,或者通过递归向上直到parent为null的函数,然后反转遇到的节点的array/list
  • 差不多吧

    UPD: 并连接最终列表以获得最终xpath。
    不要认为属性是个问题

    我曾经做过类似的工作。使用的主要思想是可以在xpath中使用元素的索引。例如,在下面的xml中

    <root>
        <el />
        <something />
        <el />
    </root>
    
    
    
    第二个
    的xpath将是
    /root[1]/el[2]
    (xpath索引基于1)。它的意思是“取第一个根,然后从所有名为el的元素中取第二个根”。因此元素
    某物
    不会影响元素
    el
    的索引。因此,理论上可以为xml中的每个特定元素创建xpath。在实践中,我通过递归遍历树并记住有关元素及其索引的信息来实现这一点。

    创建引用元素特定属性的xpath只是将“/@attrName”添加到元素的xpath中。

    我编写了一个方法来返回库中元素的绝对路径。为了让您了解它的工作原理,这里有一个摘录:


    因此,您可以在文档中递归,应用测试,并使用它返回XPath。或者,可能更好的是,您可以使用同一个库中的。更新:

    <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vApos">'</xsl:variable>
    
        <xsl:template match="*[@* or not(*)] ">
          <xsl:if test="not(*)">
             <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
             <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
             <xsl:text>&#xA;</xsl:text>
            </xsl:if>
            <xsl:apply-templates select="@*|*"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
             "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings">
                <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
            <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    
    <root>
        <elemA>one</elemA>
        <elemA attribute1='first' attribute2='second'>two</elemA>
        <elemB>three</elemB>
        <elemA>four</elemA>
        <elemC>
            <elemB>five</elemB>
        </elemC>
    </root>
    
    /root/elemA='one'
    /root/elemA[2]='two'
    /root/elemA[2][@attribute1='first']
    /root/elemA[2][@attribute2='second']
    /root/elemB='three'
    /root/elemA[3]='four'
    /root/elemC/elemB='five'
    
    <root>
        <elemX serial="kefw90234kf2esda9231">
            <id>89734</id>
        </elemX>
    </root>
    
    /root/elemX='89734'
    /root/elemX[@serial='kefw90234kf2esda9231']
    
    /root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
    /root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
    'myNamespace']
    
    @Mrade已经更新了他的问题。下面是一个解决方案:

    此XSLT转换

    <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vApos">'</xsl:variable>
    
        <xsl:template match="*[@* or not(*)] ">
          <xsl:if test="not(*)">
             <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
             <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
             <xsl:text>&#xA;</xsl:text>
            </xsl:if>
            <xsl:apply-templates select="@*|*"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
             "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings">
                <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
            <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    
    <root>
        <elemA>one</elemA>
        <elemA attribute1='first' attribute2='second'>two</elemA>
        <elemB>three</elemB>
        <elemA>four</elemA>
        <elemC>
            <elemB>five</elemB>
        </elemC>
    </root>
    
    /root/elemA='one'
    /root/elemA[2]='two'
    /root/elemA[2][@attribute1='first']
    /root/elemA[2][@attribute2='second']
    /root/elemB='three'
    /root/elemA[3]='four'
    /root/elemC/elemB='five'
    
    <root>
        <elemX serial="kefw90234kf2esda9231">
            <id>89734</id>
        </elemX>
    </root>
    
    /root/elemX='89734'
    /root/elemX[@serial='kefw90234kf2esda9231']
    
    /root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
    /root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
    'myNamespace']
    
    当@c0mrade应用于新提供的文档时

    <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vApos">'</xsl:variable>
    
        <xsl:template match="*[@* or not(*)] ">
          <xsl:if test="not(*)">
             <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
             <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
             <xsl:text>&#xA;</xsl:text>
            </xsl:if>
            <xsl:apply-templates select="@*|*"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
             "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings">
                <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
            <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    
    <root>
        <elemA>one</elemA>
        <elemA attribute1='first' attribute2='second'>two</elemA>
        <elemB>three</elemB>
        <elemA>four</elemA>
        <elemC>
            <elemB>five</elemB>
        </elemC>
    </root>
    
    /root/elemA='one'
    /root/elemA[2]='two'
    /root/elemA[2][@attribute1='first']
    /root/elemA[2][@attribute2='second']
    /root/elemB='three'
    /root/elemA[3]='four'
    /root/elemC/elemB='five'
    
    <root>
        <elemX serial="kefw90234kf2esda9231">
            <id>89734</id>
        </elemX>
    </root>
    
    /root/elemX='89734'
    /root/elemX[@serial='kefw90234kf2esda9231']
    
    /root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
    /root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
    'myNamespace']
    
    说明

    <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vApos">'</xsl:variable>
    
        <xsl:template match="*[@* or not(*)] ">
          <xsl:if test="not(*)">
             <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
             <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
             <xsl:text>&#xA;</xsl:text>
            </xsl:if>
            <xsl:apply-templates select="@*|*"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
             "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings">
                <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
            <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    
    <root>
        <elemA>one</elemA>
        <elemA attribute1='first' attribute2='second'>two</elemA>
        <elemB>three</elemB>
        <elemA>four</elemA>
        <elemC>
            <elemB>five</elemB>
        </elemC>
    </root>
    
    /root/elemA='one'
    /root/elemA[2]='two'
    /root/elemA[2][@attribute1='first']
    /root/elemA[2][@attribute2='second']
    /root/elemB='three'
    /root/elemA[3]='four'
    /root/elemC/elemB='five'
    
    <root>
        <elemX serial="kefw90234kf2esda9231">
            <id>89734</id>
        </elemX>
    </root>
    
    /root/elemX='89734'
    /root/elemX[@serial='kefw90234kf2esda9231']
    
    /root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
    /root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
    'myNamespace']
    
    • 仅匹配和处理没有子元素或具有属性的元素

    • 对于任何这样的元素,如果它没有子元素,那么它的所有祖先元素或自身元素都将以一种名为
      'path'
      的特定模式进行处理。然后输出
      “='theValue'”
      部分,然后输出一个NL字符

    • 然后处理匹配元素的所有属性

    • 最后,模板应用于所有子元素

    • 'path'
      模式下处理元素非常简单
      :输出
      /
      字符和元素名称。然后,如果前面有同名的同级,则输出“[numprecshibles+1]”部分

    • 属性的处理很简单:首先在
      'path'
      模式下处理其父元素的所有
      祖先或自身:
      元素,然后输出[attrName=attrValue]部分,后面是NL字符

    注意事项

    <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vApos">'</xsl:variable>
    
        <xsl:template match="*[@* or not(*)] ">
          <xsl:if test="not(*)">
             <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
             <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
             <xsl:text>&#xA;</xsl:text>
            </xsl:if>
            <xsl:apply-templates select="@*|*"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
             "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings">
                <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
            <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    
    <root>
        <elemA>one</elemA>
        <elemA attribute1='first' attribute2='second'>two</elemA>
        <elemB>three</elemB>
        <elemA>four</elemA>
        <elemC>
            <elemB>five</elemB>
        </elemC>
    </root>
    
    /root/elemA='one'
    /root/elemA[2]='two'
    /root/elemA[2][@attribute1='first']
    /root/elemA[2][@attribute2='second']
    /root/elemB='three'
    /root/elemA[3]='four'
    /root/elemC/elemB='five'
    
    <root>
        <elemX serial="kefw90234kf2esda9231">
            <id>89734</id>
        </elemX>
    </root>
    
    /root/elemX='89734'
    /root/elemX[@serial='kefw90234kf2esda9231']
    
    /root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
    /root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
    'myNamespace']
    
    • 命名空间中的名称以其初始可读形式显示,没有任何问题

    • 为了提高可读性,从不显示
      [1]
      索引


    以下是我的初步答案(可能被忽略)

    这里是一个纯XSLT 1.0解决方案

    <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="vApos">'</xsl:variable>
    
        <xsl:template match="*[@* or not(*)] ">
          <xsl:if test="not(*)">
             <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
             <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
             <xsl:text>&#xA;</xsl:text>
            </xsl:if>
            <xsl:apply-templates select="@*|*"/>
        </xsl:template>
    
        <xsl:template match="*" mode="path">
            <xsl:value-of select="concat('/',name())"/>
            <xsl:variable name="vnumPrecSiblings" select=
             "count(preceding-sibling::*[name()=name(current())])"/>
            <xsl:if test="$vnumPrecSiblings">
                <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
            </xsl:if>
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>
            <xsl:value-of select="concat('[@',name(), '=',$vApos,.,$vApos,']')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    </xsl:stylesheet>
    
    <root>
        <elemA>one</elemA>
        <elemA attribute1='first' attribute2='second'>two</elemA>
        <elemB>three</elemB>
        <elemA>four</elemA>
        <elemC>
            <elemB>five</elemB>
        </elemC>
    </root>
    
    /root/elemA='one'
    /root/elemA[2]='two'
    /root/elemA[2][@attribute1='first']
    /root/elemA[2][@attribute2='second']
    /root/elemB='three'
    /root/elemA[3]='four'
    /root/elemC/elemB='five'
    
    <root>
        <elemX serial="kefw90234kf2esda9231">
            <id>89734</id>
        </elemX>
    </root>
    
    /root/elemX='89734'
    /root/elemX[@serial='kefw90234kf2esda9231']
    
    /root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
    /root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
    'myNamespace']
    
    下面是一个示例xml文档和一个样式表,它接受一个节点集参数,并为每个成员节点生成一个有效的XPath表达式

    样式表(buildPath.xsl):



    上周,我做了完全相同的事情,将xml处理为符合solr的格式

    因为你想要一个伪代码:我就是这样做到的

    //您可以跳过对父对象和子对象的引用

    1\初始化自定义节点对象:NodeObjectVO{String nodeName,String path,List attr,NodeObjectVO parent,List child}

    2_uu创建一个空列表

    3_u创建xml的dom表示,并通过该节点进行迭代。对于每个节点,获取相应的信息。所有信息(如节点名称、属性名称和值)都应该可以从dom对象中获得。(您需要检查dom节点类型,代码应忽略处理指令和纯文本节点。)

    //代码膨胀警告。 4_u唯一棘手的部分是获取路径。我创建了一个迭代实用程序方法来从NodeElement获取xpath字符串。(While(node.Parent!=null){path+=node.Parent.nodeName}

    (您还可以通过维护一个全局路径变量来实现这一点,该变量保持跟踪