首页 > 解决方案 > XPath 选择:相对路径不适用于跟随兄弟

问题描述

我已经多次看到这个问题被问过,但方式略有不同。看看类似的例子,我仍然缺少一些东西。

使用以下信息,我正在尝试执行 XPath 1.0 选择以从带有帐户的 XML 中获取一组唯一的客户帐户值。使用模板、for-each 和 Muenchian 分组来执行 XSLT 是不可能的。

我有这个 XML:

<?xml version="1.0" encoding="utf-8"?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/Message">
    <Body xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/Message">
        <MessageParts xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/Message">
            <ReportArchive xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/ReportArchive">
                <Report class="entity">
                    <_DocumentHash>d1fd3992e1d6cde8fd06512cea125792</_DocumentHash>
                    <ReportSection class="entity">
                        <Name>AddressBody</Name>
                        <Type>Body</Type>
                        <ReportSectionField class="entity">
                            <Name>CustTable_AccountNum</Name>
                            <Value>0000000001</Value>
                        </ReportSectionField>
                    </ReportSection>
                    <ReportSection class="entity">
                        <Name>AddressBody</Name>
                        <Type>Body</Type>
                        <ReportSectionField class="entity">
                            <Name>CustTable_AccountNum</Name>
                            <Value>0000000001</Value>
                        </ReportSectionField>
                    </ReportSection>
                    <ReportSection class="entity">
                        <Name>AddressBody</Name>
                        <Type>Body</Type>
                        <ReportSectionField class="entity">
                            <Name>CustTable_AccountNum</Name>
                            <Value>0000000002</Value>
                        </ReportSectionField>
                    </ReportSection>
                    <ReportSection class="entity">
                        <Name>AddressBody</Name>
                        <Type>Body</Type>
                        <ReportSectionField class="entity">
                            <Name>CustTable_AccountNum</Name>
                            <Value>0000000003</Value>
                        </ReportSectionField>
                    </ReportSection>
                    <ReportSection class="entity">
                        <Name>AddressBody</Name>
                        <Type>Body</Type>
                        <ReportSectionField class="entity">
                            <Name>CustTable_AccountNum</Name>
                            <Value>0000000004</Value>
                        </ReportSectionField>
                    </ReportSection>
                    <ReportSection class="entity">
                        <Name>AddressBody</Name>
                        <Type>Body</Type>
                        <ReportSectionField class="entity">
                            <Name>CustTable_AccountNum</Name>
                            <Value>0000000005</Value>
                        </ReportSectionField>
                    </ReportSection>
                </Report>
            </ReportArchive>
        </MessageParts>
    </Body>
</Envelope>

使用这个 XPath:(//*[local-name()='ReportSectionField'][./*[local-name()='Name'] = 'CustTable_AccountNum']/*[local-name()='Value'])[not(. = following-sibling::*)]/text()

使用“()”,我的假设是相对路径选择将创建一个节点集,然后“not()”过滤器部分将解析结果集中的每个兄弟并返回唯一值。当我使用“following-sibling”轴时,这会失败,但“following”轴有效。我不想遍历后代,所以“跟随”不是我想要使用的轴。我错过了什么,有人可以帮我想象发生了什么吗?

其他需要注意的事项: - XPath 编译器是 BizTalk 使用的基于 .Net (1.0) 的(请参阅本文了解原因:XPath 和 XSLT 2.0 for .NET?

标签: xmlxpathxpath-1.0

解决方案


XPath 寻址源文档中的节点。因此,相对于所选value元素,您仍然需要查看following::轴,因为其他value元素不是同级元素。

在选择要比较值的元素时,您可以将 XPath 调整得更具体一点,方法value是“向上跳”到ReportSection元素,然后查看following-sibling::*满足相同选择标准的value元素以查找要比较和过滤的元素:

//*[local-name() = 'ReportSectionField' and 
      *[local-name() = 'Name' and . = 'CustTable_AccountNum']]/
    *[local-name() = 'Value' and 
      not(. = ../../following-sibling::*/
                *[local-name() = 'ReportSectionField' and  
                    *[local-name() = 'Name' and . = 'CustTable_AccountNum']]/
                  *[local-name() = 'Value']
       )
     ]/text()

推荐阅读