Search code examples
xmlxsltcomparexslt-2.0

XSLT compare input xml data values against external xml document


I am trying to use following input.xml in xslt and compare it against list.xml for validation with in XSLT. Confused with how to achieve it. I have tried using keys or comparable xslt functions but to failure. I have described What need to be achieved in XSLT snippet below.

list.xml

<rows>
 <row>
  <code>0155</code>
 </row>
 <row>
  <code>0156</code>
 </row>
 <row>
  <code>0158</code>
 </row>
<rows>

input.xml

<WBS>
    <IDOC>
        <segment>
            <cc>0154</cc>
        </segment>
        <segment>
            <cc>0155</cc>
        </segment>
        <segment>
            <cc>0156</cc>
        </segment>
    </IDOC>
    <IDOC>
        <segment>
            <cc>0101</cc>
        </segment>
        <segment>
            <cc>0102</cc>
        </segment>
    </IDOC>
    <IDOC>
        <segment>
            <cc>0156</cc>
        </segment>
    </IDOC>
</WBS>

XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" media-type="string" encoding="UTF-8" indent="yes"/>

    <xsl:param name="listText" select="doc('list.xml')"/>
    <xsl:variable name="list" select="$listText"/>

    <xsl:template match="/">
        <xsl:for-each select="./WBS">
            <xsl:element name="WBSData">
                <xsl:for-each select="./*:IDOC">
                    <xsl:element name="isValid">
                            <xsl:value-of select=""/> <!-- false if all //segment/cc values does not exists in list.xml/rows/row/code -->
                    </xsl:element>
                    <xsl:for-each select="./*:segment">
                        <!-- do for-each for /segment only when segment/cc value is part of list.xml/rows/row/code-->
                            <xsl:element name="data">

                            </xsl:element>
                    </xsl:for-each>

                </xsl:for-each>
            </xsl:element>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Solution

  • Here's how you could do this (although your sample XSLT must be missing some parts for the ouptut to make sense) :

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        version="1.0"
        exclude-result-prefixes="xs">
    
      <xsl:output method="xml" indent="yes"/>
    
      <!-- Declaring 'list.xml' data inline for testing. -->
      <!-- <xsl:variable name="list" select="doc('list.xml')"/> -->
      <xsl:variable name="list">
        <rows>
          <row>
            <code>0155</code>
          </row>
          <row>
            <code>0156</code>
          </row>
          <row>
            <code>0158</code>
          </row>
        </rows>
      </xsl:variable>
      <xsl:variable name="listCodes" select="$list/rows/row/code"/>
    
      <xsl:template match="WBS">
        <WBSData>
           <xsl:apply-templates/>
        </WBSData>
      </xsl:template>
    
      <xsl:template match="IDOC">
          <isValid>
            <xsl:value-of select="segment/cc=$listCodes"/>
          </isValid>
          <xsl:apply-templates select="segment/cc[.=$listCodes]"/>
      </xsl:template>
    
      <xsl:template match="segment/cc">
          <data>
            <xsl:value-of select="."/>
          </data>
      </xsl:template>
    
    </xsl:stylesheet>
    

    See it working here : https://xsltfiddle.liberty-development.net/ehVZvw6