Home > Blockchain >  XSLT compare lists and output single node
XSLT compare lists and output single node

Time:05-05

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>

CodePudding user response:

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>
  • Related