我需要使用方法(DEST id =“RUSSIA”method =提取最深层嵌套的元素节点(XSLT,xpath,xquery ...最好是xpath) “删除”/>)和他的直接祖先(SOURCE id =“AFRICA”method =“modify”>)。
我不想使用方法获取顶级节点(main method =“modify”>或main method =“modify”>)。
使用方法的最深嵌套元素对应于实际操作。 带方法的顶级元素实际上是虚拟动作,不能被考虑在内。
这是我的XML示例文件:
<?xml version="1.0" encoding="UTF-8"?>
<main method="modify">
<MACHINE method="modify">
<SOURCE id="AFRICA" method="modify">
<DEST id="RUSSIA" method="delete"/>
<DEST id="USA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="AUSTRALIA" method="modify"/>
<DEST id="CANADA" method="create"/>
</SOURCE>
</MACHINE>
</main>
这是我期望的Xpath输出:
<SOURCE id="AFRICA" method="modify"><DEST id="RUSSIA" method="delete"/>
<SOURCE id="AFRICA" method="modify"><DEST id="USA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="AUSTRALIA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="CANADA" method="create"/>
我当前的xpath命令无法提供足够的结果。
返回的命令xpath(“// [@ method] / ancestor :: *”):
<main><MACHINE method="modify"> # NOT WANTED
<MACHINE method="modify"><SOURCE id="AFRICA" method="modify"> # NOT WANTED
<MACHINE method="modify"><SOURCE id="USA" method="modify"> # NOT WANTED
<SOURCE id="AFRICA" method="modify"><DEST id="RUSSIA" method="delete"/>
<SOURCE id="AFRICA" method="modify"><DEST id="USA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="AUSTRALIA" method="modify"/>
<SOURCE id="USA" method="modify"><DEST id="CANADA" method="create"/>
我的xmltwig代码以获取更多信息(上下文):
#!/usr/bin/perl -w
use warnings;
use XML::Twig;
use XML::XPath;
@my $t= XML::Twig->new;
my $v= XML::Twig::Elt->new;
$t-> parsefile ('input.xml');
@abc=$t->get_xpath("\/\/[\@method]\/ancestor\:\:\*") ;
foreach $v (@abc) # outer 1
{
foreach $v ($v ->children) # internal 1
{
$w=$v->parent;
print $w->start_tag;
print $v->start_tag;
}
}
答案 0 :(得分:3)
可以使用
找到具有最大深度的节点//*[count(ancestor::*) = max(//*/count(ancestor::*))]
但它可能会表现得非常糟糕,具体取决于你的优化器有多聪明。
找到这些节点后,找到他们的祖先当然是微不足道的。但是你正在寻找比单独使用XPath更多结构的输出。
答案 1 :(得分:1)
正如我在对这个问题的评论中所提到的,我不认为这对于纯XPath是可行的,因为XPath没有像current()
函数那样允许引用它[]
限制之外的上下文。
最类似的解决方案应该是这个XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ZD="http://xyz.abc">
<xsl:output method="text"/>
<xsl:template match="//*">
<xsl:choose>
<xsl:when test="not(//*[count(ancestor::node()) > count(current()/ancestor::node())])"><xsl:value-of select="local-name(.)"/><xsl:text>
</xsl:text></xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()|@*"/>
</xsl:stylesheet>
<xsl:when>
元素找到嵌套最深的元素。例如,我输出找到的元素的本地名称,然后输出换行符,但当然你可以输出你需要的任何内容。
更新:请注意,这是基于XPath 1.0知识/工具。看来这确实可以在XPath 2.0中表达。
答案 2 :(得分:1)
一个这样的XPath2.0表达式是:
//*[not(*)
and
count(ancestor::*)
=
max(//*[not(*)]/count(ancestor::*))
]
/(self::node|..)
使用完整的XSLT 2.0示例来说明这一点:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vResult" select=
"//*[not(*)
and
count(ancestor::*)
=
max(//*[not(*)]/count(ancestor::*))
]
/(self::node|..)
"/>
<xsl:template match="/">
<xsl:sequence select="$vResult"/>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<main method="modify">
<MACHINE method="modify">
<SOURCE id="AFRICA" method="modify">
<DEST id="RUSSIA" method="delete"/>
<DEST id="USA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="AUSTRALIA" method="modify"/>
<DEST id="CANADA" method="create"/>
</SOURCE>
</MACHINE>
</main>
评估XPath表达式,并将所选元素(最大深度的元素及其父元素)复制到输出:
<SOURCE id="AFRICA" method="modify">
<DEST id="RUSSIA" method="delete"/>
<DEST id="USA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="AUSTRALIA" method="modify"/>
<DEST id="CANADA" method="create"/>
</SOURCE>
答案 3 :(得分:0)
样式表
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates
select="//DEST[@method and not(node())]"/>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="DEST[@method and not(node())]">
<xsl:apply-templates select="..">
<xsl:with-param name="leaf" select="current()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[DEST[@method and not(node())]]">
<xsl:param name="leaf"/>
<xsl:copy>
<xsl:copy-of select="@* , $leaf"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
变换
<?xml version="1.0" encoding="UTF-8"?>
<main method="modify">
<MACHINE method="modify">
<SOURCE id="AFRICA" method="modify">
<DEST id="RUSSIA" method="delete"/>
<DEST id="USA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="AUSTRALIA" method="modify"/>
<DEST id="CANADA" method="create"/>
</SOURCE>
</MACHINE>
</main>
到
<SOURCE id="AFRICA" method="modify">
<DEST id="RUSSIA" method="delete"/>
</SOURCE>
<SOURCE id="AFRICA" method="modify">
<DEST id="USA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="AUSTRALIA" method="modify"/>
</SOURCE>
<SOURCE id="USA" method="modify">
<DEST id="CANADA" method="create"/>
</SOURCE>