1

I've seen this question asked many times but in slightly different ways. Looking at similar examples, there's something I'm still missing.

With the information below, I'm trying to do a XPath 1.0 select to get a set of unique customer account values from a XML with accounts. Executing a XSLT with templates, for-each's, and using Muenchian Grouping is not possible.

I have this 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>

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

Using "()", my assumption was that the relative path select would create a node-set, and then the "not()" filter part would parse each sibling in the result set and return the unique values. When I use the "following-sibling" axis this fails, but the "following" axis works. I don't want to traverse the descendants, so "following" is not the axis I want to use. What am I missing and can someone help me visualize what's going on?

Some other things to note: - The XPath Compiler is .Net based (1.0) utilized by BizTalk (See this article for the reasons why: XPath and XSLT 2.0 for .NET?)

Sean
  • 13
  • 3

1 Answers1

0

XPath addresses the nodes in the source document. So, relative from the selected value element, you would still need to look at the following:: axis, since the other value elements are not siblings.

You could adjust the XPath to be a bit more specific when selecting the value elements to compare values against by "jumping up" to the ReportSection element, and then looking at the following-sibling::* that satisfy the same selection criteria to find value elements to compare and filter:

//*[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()
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
  • This is great and makes perfect sense. I didn't realize that the axis was still looking at the source and not my sub-select. Thanks for the help! – Sean Aug 15 '18 at 13:58