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

查看:129
本文介绍了从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)

BOUNTY:

我正在寻找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'

解释:


  • 如果节点值/文本不为null / 0,则获取xpath,add ='nodevalue'用于断言目的

  • 如果节点具有属性,则为它们创建断言

BOUNTY UPDATE:

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

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 omit-xml-declaration="yes" indent="yes"/>
    <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 应用于新提供的文档时:

When applied to the newly-provided document by @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.

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

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

处理'路径'模式中的元素很简单:输出 / 字符和元素的名称。然后,如果有同名前面的兄弟姐妹,则输出[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'中处理其父级的所有祖先或自我:: 元素模式,然后输出[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文档和一个采用节点的样式表-set参数并为每个成员节点生成一个有效的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 source(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天全站免登陆