从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>
</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>
</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>
</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>
</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>
</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>
</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>
</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>
</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>
</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>
</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>
</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>
</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}
(您还可以通过维护一个全局路径变量来实现这一点,该变量保持跟踪