从 XML 节点 java 生成/获取 xpath [英] Generate/get xpath from XML node java

查看:33
本文介绍了从 XML 节点 java 生成/获取 xpath的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm interested in advice/pseudocode code/explanation rather than actual implementation.

  • 我想查看 xml 文档及其所有节点
  • 检查节点的属性是否存在

如果节点没有属性,获取/生成带有其xpath值的字符串
如果节点确实具有属性,则遍历属性列表并为包括节点在内的每个属性创建 xpath.

Case if node doesn't have attribute, get/generate String with value of its xpath
Case if node does have attributes, iterate trough attribute list and create xpath for each attribute including the node as well.

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

Word of advice? Hopefully you will provide some useful intel

这样做的原因是..我在 jmeter 中编写自动化测试,所以对于每个请求,我需要验证该请求是否确实完成了它的工作,所以我通过使用 xpath 获取节点值来断言结果.(额外信息 -无关)

Reason for doing this is .. I'm writing automated tests in jmeter, so for every request I need to verify that request actually did its job so I'm asserting results by getting nodes values with xpath.(extra info - irrelevant)

当请求很小时,手动创建断言不是问题,但对于较大的请求,它真的很痛苦..(额外信息 - 无关)

When the request is small its not problem to create asserts by hand, but for larger ones its a really pain in the .. (extra info - irrelevant)

赏金:

我正在寻找 java 方法

I'm looking for java approach

目标

我的目标是从这个 ex xml 文件中实现以下目标:

My goal is to achieve following from this ex xml file :

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

产生以下内容:

//root[1]/elemA[1]='one'
//root[1]/elemA[2]='two'
//root[1]/elemA[2][@attribute1='first']
//root[1]/elemA[2][@attribute2='second']
//root[1]/elemB[1]='three'
//root[1]/elemA[3]='four'
//root[1]/elemC[1]/elemB[1]='five'

解释:

  • 如果节点值/文本不为空/零,则获取 xpath ,添加 = 'nodevalue' 用于断言
  • 如果节点有属性,也为它们创建断言

赏金更新:

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

I found this example, it doesn't produce the correct results , but I'm looking something like this:

http://www.coderanch.com/how-to/java/SAXCreateXPath

推荐答案

更新:

@c0mrade 更新了他的问题.这是一个解决方案:

@c0mrade has updated his question. Here is a solution to it:

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

应用于提供的 XML 文档时:

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

当@c0mrade 应用于新提供的文档时:

<root>
    <elemX serial="kefw90234kf2esda9231">
        <id>89734</id>
    </elemX>
</root>

再次产生正确的结果:

/root/elemX='89734'
/root/elemX[@serial='kefw90234kf2esda9231']

说明:

  • 仅匹配和处理没有子元素或具有属性的元素.

对于任何此类元素,如果它没有子元素,则其所有祖先元素或自身元素都以特定模式处理,名为 'path'.然后输出 "='theValue'" 部分,然后是一个 NL 字符.

For any such element, if it doesn't have children-elements all of its ancestor-or self elements are processed in a specific mode, named 'path'. Then the "='theValue'" part is output and then a NL character.

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

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

'path'模式下处理一个元素很简单:输出一个/字符和元素名称.然后,如果前面有同名的兄弟,则输出[numPrecSiblings+1]`部分.

Processing an element in the 'path' mode is simple: A / character and the name of the element are output. Then, if there are preceding siblings with the same name, a "[numPrecSiblings+1]` part is output.

属性的处理很简单:首先在'path'中处理其父元素的所有ancestor-or-self::元素code> 模式,则输出 [attrName=attrValue] 部分,后跟一个 NL 字符.

Processing of attributes is simple: First all ancestor-or-self:: elements of its parent are processed in 'path' mode, then the [attrName=attrValue] part is output, followed by a NL character.

请注意:

  • 命名空间中的名称可以毫无问题地以初始可读形式显示.

  • Names that are in a namespace are displayed without any problem and in their initial readable form.

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

To aid readability, an index of [1] is never displayed.

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

Below is my initial answer (may be ignored)

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

下面是一个示例 xml 文档和一个样式表,它采用节点集参数并为每个成员节点生成一个有效的 XPath 表达式.

Below is a sample xml document and a stylesheet that takes a node-set parameter and produces one valid XPath expression for every member-node.

样式表(buildPath.xsl):

<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
>

<xsl:output method="text"/>
<xsl:variable name="theParmNodes" select="//namespace::*[local-name() =
'myNamespace']"/>
<xsl:template match="/">
  <xsl:variable name="theResult">
    <xsl:for-each select="$theParmNodes">
    <xsl:variable name="theNode" select="."/>
    <xsl:for-each select="$theNode |
$theNode/ancestor-or-self::node()[..]">
      <xsl:element name="slash">/</xsl:element>
      <xsl:choose>
        <xsl:when test="self::*">           
          <xsl:element name="nodeName">
            <xsl:value-of select="name()"/>
            <xsl:variable name="thisPosition" 
                select="count(preceding-sibling::*[name(current()) = 
                        name()])"/>
            <xsl:variable name="numFollowing" 
                select="count(following-sibling::*[name(current()) = 
                        name()])"/>
            <xsl:if test="$thisPosition + $numFollowing > 0">
              <xsl:value-of select="concat('[', $thisPosition +
                                                           1, ']')"/>
            </xsl:if>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise> <!-- This node is not an element -->
          <xsl:choose>
            <xsl:when test="count(. | ../@*) = count(../@*)">   
            <!-- Attribute -->
              <xsl:element name="nodeName">
                <xsl:value-of select="concat('@',name())"/>
              </xsl:element>
            </xsl:when>     
            <xsl:when test="self::text()">  <!-- Text -->
              <xsl:element name="nodeName">
                <xsl:value-of select="'text()'"/>
                <xsl:variable name="thisPosition" 
                          select="count(preceding-sibling::text())"/>
                <xsl:variable name="numFollowing" 
                          select="count(following-sibling::text())"/>
                <xsl:if test="$thisPosition + $numFollowing > 0">
                  <xsl:value-of select="concat('[', $thisPosition + 
                                                           1, ']')"/>
                </xsl:if>
              </xsl:element>
            </xsl:when>     
            <xsl:when test="self::processing-instruction()">
            <!-- Processing Instruction -->
              <xsl:element name="nodeName">
                <xsl:value-of select="'processing-instruction()'"/>
                <xsl:variable name="thisPosition" 
                   select="count(preceding-sibling::processing-instruction())"/>
                <xsl:variable name="numFollowing" 
                    select="count(following-sibling::processing-instruction())"/>
                <xsl:if test="$thisPosition + $numFollowing > 0">
                  <xsl:value-of select="concat('[', $thisPosition + 
                                                            1, ']')"/>
                </xsl:if>
              </xsl:element>
            </xsl:when>     
            <xsl:when test="self::comment()">   <!-- Comment -->
              <xsl:element name="nodeName">
                <xsl:value-of select="'comment()'"/>
                <xsl:variable name="thisPosition" 
                         select="count(preceding-sibling::comment())"/>
                <xsl:variable name="numFollowing" 
                         select="count(following-sibling::comment())"/>
                <xsl:if test="$thisPosition + $numFollowing > 0">
                  <xsl:value-of select="concat('[', $thisPosition + 
                                                            1, ']')"/>
                </xsl:if>
              </xsl:element>
            </xsl:when>     
            <!-- Namespace: -->
            <xsl:when test="count(. | ../namespace::*) = 
                                               count(../namespace::*)">

              <xsl:variable name="apos">'</xsl:variable>
              <xsl:element name="nodeName">
                <xsl:value-of select="concat('namespace::*', 
                '[local-name() = ', $apos, local-name(), $apos, ']')"/>

              </xsl:element>
            </xsl:when>     
          </xsl:choose>
        </xsl:otherwise>            
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>&#xA;</xsl:text>
  </xsl:for-each>
 </xsl:variable>
 <xsl:value-of select="msxsl:node-set($theResult)"/>
</xsl:template>
</xsl:stylesheet>

xml 源代码 (buildPath.xml):

<!-- top level Comment -->
<root>
    <nodeA>textA</nodeA>
 <nodeA id="nodeA-2">
  <?myProc ?>
        xxxxxxxx
  <nodeB/>
        <nodeB xmlns:myNamespace="myTestNamespace">
  <!-- Comment within /root/nodeA[2]/nodeB[2] -->
   <nodeC/>
  <!-- 2nd Comment within /root/nodeA[2]/nodeB[2] -->
        </nodeB>
        yyyyyyy
  <nodeB/>
  <?myProc2 ?>
    </nodeA>
</root>
<!-- top level Comment -->

结果:

/root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
/root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
'myNamespace']

这篇关于从 XML 节点 java 生成/获取 xpath的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆