在 Java 中从 XML 生成/获取 Xpath

2024-04-08

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

  • 我想浏览 XML 文档及其所有节点
  • 检查节点属性是否存在

如果节点没有属性,get/generate String with value of its xpath
如果节点确实有属性,则迭代属性列表并为每个属性(包括节点)创建 xpath。

Edit

我这样做的原因是:我正在 Jmeter 中编写自动化测试,因此对于每个请求,我都需要验证该请求是否确实完成了其工作,因此我通过使用 Xpath 获取节点值来断言结果。

当请求很小时,手动创建断言不是问题,但对于较大的请求来说,这确实很痛苦。

我正在寻找 Java 方法。

Goal

我的目标是从此示例 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[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' 以用于断言目的
  • 如果节点有属性,也为它们创建断言

Update

我发现这个例子,它没有产生正确的结果,但我正在寻找这样的东西:

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


Update:

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

此 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[@serial='kefw90234kf2esda9231']
/root/elemX/id='89734'

解释:

  • 仅匹配没有子元素或具有属性的元素并进行处理。

  • 对于任何此类元素,如果它没有子元素,则将处理其所有祖先元素或 self 元素在特定模式下,名为'path'。然后"='theValue'"部分是输出,然后是 NL 字符。

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

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

  • 处理中的一个元素'path'模式很简单: A /输出字符和元素名称。然后,如果前面存在同名兄弟姐妹,则输出“[numPrecSiblings+1]”部分。

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

Do note:

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

  • 为了提高可读性,索引[1]永远不会显示。


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

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

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

样式表(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 -->

Result:

/root/nodeA[2]/nodeB[2]/namespace::*[local-name() = 'myNamespace']
/root/nodeA[2]/nodeB[2]/nodeC/namespace::*[local-name() =
'myNamespace']
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Java 中从 XML 生成/获取 Xpath 的相关文章

随机推荐

  • 如何将文本的一部分加粗 Android String

    我想将 文本的一部分加粗 但我不知道我的文本如何
  • 在 Fortran 90 中,是否必须事先声明数组维度?

    是否有必要在任何其他代码之前声明数组维度 例如 我编写了以下简化的示例代码 PROGRAM mytest IMPLICIT NONE INTEGER i j k mysum Let array c be a k by k 2 array D
  • 当我在表单中输入输入时,React 组件不必要地重新渲染

    我有一个反应组件来管理用户登录和退出 当用户在登录字段中输入电子邮件和密码时 整个组件 导航栏 在每次击键时都会重新渲染到 Dom 从而降低了速度 当用户在登录字段中输入凭据时 如何防止导航栏重新呈现 import React useCon
  • 确定一个点是否在由给定纬度/经度的 3 个点组成的三角形内

    我有 3 个点 lat lon 形成一个三角形 我如何找到一个点是否在这个三角形内 Java 代码只是三角形 即 3 个点 public static boolean pntInTriangle double px double py do
  • 使用 Devise 设置会话长度

    我的会话在 1 3 小时未使用后超时 不确定具体多长时间 我该如何调整这个 我查看了文档 似乎找不到这方面的设置 查看 config initializers devise rb 有很多配置设置 包括config timeout in 我的
  • 主线程中的Python套接字接受防止退出

    我正在使用 python 中的套接字 只是为了了解它们 然而 我真的对以下问题感到恼火 import socket soc socket socket socket AF INET soc bind localhost 8000 soc l
  • Twig,减去 2 个日期

    如何用 twig 减去两个日期 我有一个结束日期和一个开始日期 我想要两者之间的差异 例如 对于日期 2015 02 20 和 2015 02 13 我应该获得 7 我怎样才能做到这一点 感谢帮助 第一个解决方案 推荐 使用现有库 您可以使
  • 函数模板专门化类型 - 是可选的吗?

    Is the
  • 重置 HTML5 无效输入状态

    经过验证的输入最初不会被标记为无效 直到值发生更改 如何恢复这个初始状态 我的问题的详细信息 我有一个简单的订单 如果用户单击 添加项目 按钮 我将克隆第一个项目并清空输入字段 但由于我使用的是 html5 验证 清空会使它们无效 这是单击
  • 用于 BroadcastReceiver 的 Firebase 云消息传递意图过滤器是什么?

    我试图在 Android 系统收到 Firebase Cloud 消息通知时运行 Android BroadcastReceiver public class MyBroadcastReceiver extends BroadcastRec
  • 在 Android 上使用 Canvas 绘制两条线之间的区域

    我正在为我的应用程序开发一个简单的统计图形类 我尝试过 aChartEngine 和其他更多 但我更喜欢使用我自己的类 我正在使用包含 Android 的 Canvas 类绘制图形 但问题是我不知道如何填充线条和底部边框之间的区域 现在 矩
  • 在现有工作区上使用新 Eclipse 时如何重新附加 subclipse

    我的工作区中有一些项目是使用 Subclipse 从 SVN 导入的 现在 我使用新版本的 Eclipse 带有 Subclipse 打开此工作区 并且 团队 上下文菜单仅包含 应用补丁 有没有办法让 subclipse 处理这些项目 而无
  • Angular 2:防止路由器添加到历史记录

    我们有一个客户 在我们的应用程序中使用 iFraming 访问他们的网站 他们不希望我们应用程序中的路由器导航影响他们自己网站的后退按钮导航 我们尝试了几种方法 包括使用发布消息来尝试在history back 被触发时让iFrame与父窗
  • 忽略 Inf 值并运行 lm 回归

    这些是我的变量 gt dput y c 22 0713165394207 14 0880914427811 10 9650636244176 1 96648890706268 5 30593850426708 7 5465191603778
  • @MainActor 类是对主要参与者的扩展吗?

    如果正在上课 MainActor MainActor class MyClass NSObject 这是否将其所有扩展放在 MainActor还有 extension MyClass Yes As SE 0316 全球演员 https gi
  • 无法更改购物车总计中的 WooCommerce 优惠券标签

    事实证明 这是一个我无法解决的挑战 我几乎在其他地方都处理过将 优惠券 重命名为 促销 的工作 然而 调用优惠券名称和LABEL的WC LABEL的重命名就困难了很多 这是我正在谈论的内容的屏幕截图 我几乎已将站点范围内 优惠券 的所有用途
  • 为什么预期的字符串变成元组[重复]

    这个问题在这里已经有答案了 我预计变量output format成为一个字符串 但是当我运行脚本时它给了我一个tuple类型并抛出异常 如果我在 Python 解释器中运行 它会给我一个预期的字符串 sout standard access
  • 使用 PHP 内置 Web 服务器进行无脂路由

    我正在学习 fatfree 的路线 发现它的表现出乎意料 这是我在index php中的代码 f3 require once dirname dirname FILE lib base php f3 Base instance echo r
  • 如何将 UIView 出口连接到自定义子视图

    我还是 xcode iOS 新手 并且有以下问题 为了显示一些移动调试信息 我将 UIview 作为出口属性添加 连接到我的视图控制器之一 该视图是 UIview 的自定义子类 现在 我添加了一些 UIlabels 作为子视图到该视图中 并
  • 在 Java 中从 XML 生成/获取 Xpath

    我对建议 伪代码代码 解释而不是实际实现感兴趣 我想浏览 XML 文档及其所有节点 检查节点属性是否存在 如果节点没有属性 get generate String with value of its xpath如果节点确实有属性 则迭代属性