0

I am trying to transform a XML document with data that has coded values. I have a second external document with those values decoded. I want to search the external file to match an element value (QuantityUnitOfMeasure/Code) from the processing file with element value(root/row/NCItCode) from the external document to ultimately return a sibling element(/root/row/NCIDefinition) from the external file. This is not working, new to XSLT.

Code:

<?xml version="1.0" encoding="UTF-8"?>
    
<xsl:variable name="externalDoc" select="document('NCPDP.xml')"/>    

<xsl:for-each select="Quantity">            
   <span>Quantity Unit Of Measure Code   : </span>
   <span> <xsl:value-of select="QuantityUnitOfMeasure/Code"/> </span>            
   <br></br>
   <xsl:for-each select="$externalDoc/root/row">
      <xsl:if test="NCItCode=QuantityUnitOfMeasure/Code">
         <span> <xsl:value-of select="NCIDefinition"/> </span>
      </xsl:if>
</xsl:for-each>

Processing XML:

<Quantity>
   <Value>300</Value>
   <CodeListQualifier>38</CodeListQualifier>
   <QuantityUnitOfMeasure>
      <Code>C48672</Code>
   </QuantityUnitOfMeasure>
</Quantity>

ExternalXML File (NCPDP.xml):

<root>
  <row>
    <NCItCode>C48672</NCItCode>
    <NCPDPPreferredTerm>Schedule I Substance</NCPDPPreferredTerm>
    <NCIDefinition>
       A category of drugs not considered legitimate for medical use.
    </NCIDefinition>
  </row>
<root>

Expected results:

Quantity Unit Of Measure Code   : C48672
A category of drugs not considered legitimate for medical use.
S A
  • 3
  • 2
  • 1
    Please post a [mcve] showing an example of both XML documents and the expected output. Also clarify the logic that needs to be applied here. – michael.hor257k Jun 16 '21 at 01:23
  • Needs some details, e.g. is the URI of the external document known to the calling application, or is it contained in the content of the "primary" document. Either way, read up on the document() function. – Michael Kay Jun 16 '21 at 07:45
  • It's getting *somewhat* clearer. Now the question is: does your processor support XSLT 2.0? – michael.hor257k Jun 16 '21 at 14:20
  • I believe I need to assume no. XSLT 1.0 only – S A Jun 16 '21 at 14:30
  • Why assume when you can check: https://stackoverflow.com/a/25245033/3016153 – michael.hor257k Jun 16 '21 at 15:00
  • THANK YOU!! I have some security issues to resolve regarding the document function (xsltsettings.enabledocumentfunction) but your method and code was well explained. Thanks again for the help, advise and patience with a newbie. – S A Jun 16 '21 at 16:10

1 Answers1

0

Consider the following example:

Input XML

<Quantities>
    <Quantity>
       <Value>300</Value>
       <CodeListQualifier>38</CodeListQualifier>
       <QuantityUnitOfMeasure>
          <Code>XYZ</Code>
       </QuantityUnitOfMeasure>
    </Quantity>
    <Quantity>
       <Value>300</Value>
       <CodeListQualifier>38</CodeListQualifier>
       <QuantityUnitOfMeasure>
          <Code>C48672</Code>
       </QuantityUnitOfMeasure>
    </Quantity>
</Quantities>

NCPDP.xml (corrected to be well-formed!!!)

<root>
  <row>
    <NCItCode>C48672</NCItCode>
    <NCPDPPreferredTerm>Schedule I Substance</NCPDPPreferredTerm>
    <NCIDefinition>
       A category of drugs not considered legitimate for medical use.
    </NCIDefinition>
  </row>
</root>

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:param name="externalDoc" select="document('NCPDP.xml')"/>    
                                           
<xsl:template match="/Quantities">
    <root>
        <xsl:for-each select="Quantity">            
            <span>Quantity Unit Of Measure Code   : </span>
            <span> 
                <xsl:value-of select="QuantityUnitOfMeasure/Code"/>
            </span>            
            <br/>
            <xsl:variable name="ext-entry" select="$externalDoc/root/row[NCItCode=current()/QuantityUnitOfMeasure/Code]" />
            <xsl:if test="$ext-entry">
                 <span> 
                    <xsl:value-of select="$ext-entry/NCIDefinition"/> 
                 </span>
            </xsl:if>
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>

Result

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <span>Quantity Unit Of Measure Code   : </span>
  <span>XYZ</span>
  <br/>
  <span>Quantity Unit Of Measure Code   : </span>
  <span>C48672</span>
  <br/>
  <span>
       A category of drugs not considered legitimate for medical use.
    </span>
</root>

Alternatively, you could use a key to perform the lookup - although this is a bit tricky in XSLT 1.0, where keys work only in the current document:

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:param name="externalDoc" select="document('NCPDP.xml')"/>   
 
<xsl:key name="k1" match="row" use="NCItCode" />
                                          
<xsl:template match="/Quantities">
    <root>
        <xsl:for-each select="Quantity">            
            <span>Quantity Unit Of Measure Code   : </span>
            <span> 
                <xsl:value-of select="QuantityUnitOfMeasure/Code"/>
            </span>            
            <br/>
            <xsl:variable name="code" select="QuantityUnitOfMeasure/Code" />
            <!-- switch context to the external document in order to use key -->
            <xsl:for-each select="$externalDoc">
                <xsl:variable name="ext-entry" select="key('k1', $code)" />
                <xsl:if test="$ext-entry">
                     <span> 
                        <xsl:value-of select="$ext-entry/NCIDefinition"/> 
                     </span>
                </xsl:if>
            </xsl:for-each> 
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51