Gnomejon
Gnomejon

Reputation: 123

XSLT compare lists and output single node

I'm trying to compare 2 lists and if there are 1 or more nodes that do not appear in the other list I want to output a single node in the resulting xml.

Example XML:

<Root>
  <Layers>
    <List1>
      <Name>test1</Name>
      <Name>test2</Name>
      <Name>test3</Name>
    </List1>
  </Layers>
  <MoreLayers>
    <List2>
      <Name>test1</Name>
      <Name>test4</Name>
      <Name>test5</Name>
    </List2>
  </MoreLayers>
</Root>

Which should see that test2 and test3 don't appear in List2 and give the following output:

<RootOut>
  <UniqueNames>Yes</UniqueNames>
</RootOut>

I've tried using a for-each loop on List1 and doing a key comparison with List2, but this ends up creating 1 node per unique name, so would output 2 <UniqueNames>Yes</UniqueNames> nodes in the output. I'm sure there's something easy I'm missing, but I can't figure it out.

XSLT:

  <xsl:variable name="list1_names" select="/Root/Layers/List1/Name"/>

  <xsl:key name="list2_lookup" match="/Root/MoreLayers/List2" use="Name"/>

  <xsl:template match="/*">
    <RootOut>
      <xsl:call-template name="UniqueNames" />
    </policy>
  </xsl:template>

  <xsl:template name="UniqueNames">
        <xsl:for-each select="$list1_names">
          <xsl:if test="(not(key( 'list2_lookup', Name )))">
            <UniqueNames>Yes</UniqueNames>
          </xsl:if>
        </xsl:for-each>
  </xsl:template>

Upvotes: 0

Views: 115

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 116957

How about simply:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="list2" match="List2/Name" use="." />

<xsl:template match="/Root">
    <RootOut>
        <xsl:if test="Layers/List1/Name[not(key('list2', .))]">
            <UniqueNames>Yes</UniqueNames>
        </xsl:if>
    </RootOut>
</xsl:template>

</xsl:stylesheet>

Note that this only tests if there are Names in List1 that do not appear in List2, not the other way round (your description is somewhat vague on this point).


Another option is to look at it from the opposite direction:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="list1" match="List1/Name" use="." />

<xsl:template match="/Root">
    <RootOut>
        <xsl:if test="count(Layers/List1/Name) > count(key('list1', MoreLayers/List2/Name))">
            <UniqueNames>Yes</UniqueNames>
        </xsl:if>
    </RootOut>
</xsl:template>

</xsl:stylesheet>

Upvotes: 2

Related Questions