I've seen this question Dimitre Novatchev展示了一种使用XPath 1.0表达式复制ends-with
的方法。但是,我在SelectNodes
调用的情况下无法实现它。
以前我在使用
XmlElement root = doc.DocumentElement;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", root.NamespaceURI);
XmlNodeList nodeList = doc.SelectNodes("//x:*[contains(name(.), '-notification')]", nsmgr);
返回了我想要的所有节点加上我没有返回的节点(has-more-notifications
)。
所以我尝试使用Dimitre表达式给了我:
XmlNodeList nodeList = doc.SelectNodes("//x:*[substring(name(.), string-length(name(.)) - string-length('-notification') +1)]", nsmgr);
哪个失败了,给了我notification-data-response
的根节点。
这是我第一次涉足XPath,它似乎就像正则表达式 - 你要么理解它,要么你不理解它。
如何实现表达式,使其仅返回以-notification
结尾的节点?
更新
输入样本:
<?xml version="1.0" encoding="UTF-8"?>
<notification-data-response xmlns="http://checkout.google.com/schema/2" serial-number="16ceae10-a9f1-4ff0-a77b-c3407f2d684a">
<notifications>
<new-order-notification serial-number="653417067275702-00001-7">
</new-order-notification>
<order-state-change-notification serial-number="653417067275702-00005-1">
</order-state-change-notification>
<risk-information-notification serial-number="653417067275702-00005-5">
</risk-information-notification>
<authorization-amount-notification serial-number="653417067275702-00005-6">
</authorization-amount-notification>
</notifications>
<continue-token>CP6u9NeQJxC2y72h-MiUARgG</continue-token>
<has-more-notifications>false</has-more-notifications>
</notification-data-response>
答案 0 :(得分:2)
如果要避免使用名称空间前缀,则必须使用local-name()函数。这样的事情应该为你提供以-notification
结尾的所有节点// node()[substring(local-name(),string-length(local-name()) - string-length(' - notification')+ 1,string-length(local-name()))= '-notification']
好的..我在这里测试了这个。您也可以验证.XPath是一个开放标准,因此所有工具都应该能够给出类似的响应。
http://www.xpathtester.com/test
INPUT
<?xml version="1.0"?>
<notification-data-response xmlns:x="test">
<TPI_ADDRESSES>
<ISPRIMARY>Y</ISPRIMARY>
<data1>
<x:wewe-notification/>
</data1>
<data2>
<x:wewe-notification/>
</data2>
</TPI_ADDRESSES>
</notification-data-response>
输出
<?xml version="1.0" encoding="UTF-8"?>
<root>
<x:wewe-notification xmlns:x="test"/>
<x:wewe-notification xmlns:x="test"/>
</root>
忽略根节点,因为生成它以呈现有效的可形成响应。
现在让我分解并向你解释xpath:
“//” - 表示您正在搜索狂野搜索或我们称之为完全扫描...就像您没有 关心目标节点到达什么级别。
“node()” - 是对任何节点或当前节点的引用....
所以现在: “// node()” - 一起表示你将评估xml中的所有节点。
你评价什么?
名称 - 您想要查找节点的名称中是否包含“-notification”。为此,您使用LHS中的子字符串函数
substring(local-name(),string-length(local-name()) - string-length(' - notification')+ 1,string-length(local-name()))
RHS是你搜索string =' - notification'
local-name()=给出您在除前缀之外的任何点评估的节点的名称 string-length() - 节点名称的长度
答案 1 :(得分:0)
Dimitre的解决方法效果很好。您只需要将子结构的“结束”与您要查找的字符串常量进行比较,即:
SelectNodes("//x:*['-notification'=substring(name(.), string-length(name(.))
- string-length('-notification') +1)]")
出于兴趣,如果您可以通过更具体的路径来避免//
通配符,那么您将在大型文档上显着提高查询的性能。
修改强>
以下是我测试的方法(在MS Visual Studio的xslt解析器中,为1.0):
<root>
<nodeendsin-notification></nodeendsin-notification>
<alsonodeendsin-notification></alsonodeendsin-notification>
<nopethisis-notifications></nopethisis-notifications>
<idontcontainatall></idontcontainatall>
</root>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/root">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="*['-notification'=substring(name(.), string-length(name(.)) - string-length('-notification') +1)]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()">
</xsl:template>
</xsl:stylesheet>
仅返回以'notification'结尾的节点
<root>
<nodeendsin-notification></nodeendsin-notification>
<alsonodeendsin-notification></alsonodeendsin-notification>
</root>