Search code examples
xmlxsltbiztalkbiztalk-2010

xsl:if not working as expected


I have the following XML I am trying to transform into an internal canonical format. What I need to do is test the 'id' node in the assignedAuthor section for a specific root string and grab the extension attribute based on that. I have to use XSLT 1.0 because I am using the BizTalk mapper to run this XSLT.

Here is the XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ClinicalDocument xmlns="urn:hl7-org:v3">
  <component>
    <structuredBody>
      <component>
        <section>
          <entry>
            <act>
              <author>
                <assignedAuthor>
                  <id root="1.2.840.113619.21.1.4780296594025264329.2.2" extension="1609858104000010"/> 
                  <id root="2.16.840.1.113883.4.6" extension="1437282605"/>
                </assignedAuthor>
              </author>
            </act>
          </entry>
        </section>
      </component>
    </structuredBody>
  </component>
</ClinicalDocument>

Here is how I want it to look transformed (The NPI is just the extension attribute of the id node who's root attribute equals "2.16.840.1.113883.4.6"):

<ns13:Insert>
  <ns13:Rows>
    <ns13:NPI>1437282605</NPI>
  </ns13:Rows>
</ns13:Insert>

When I use this XSLT (without the overarching templates and such):

<ns13:Insert>
  <ns13:Rows>
<xsl:for-each select="*/*[local-name()='author']/*[local-name()='assignedAuthor']/*[local-name()='id']">
   <xsl:if test="../*[local-name()='id']/@root">
      <ns13:NPI>
         <xsl:value-of select="./@extension" />
      </ns13:NPI>
    </xsl:if>
  </xsl:for-each>
  </ns13:Rows>
</ns13:Insert>

I get this result (this is expected because I am not testing for the specific root attribute string):

<ns13:Insert>
  <ns13:Rows>
    <ns13:NPI>1609858104000010</ns13:NPI>
    <ns13:NPI>1437282605</ns13:NPI>
  </ns13:Rows>
</ns13:Insert>

But when I try to use this if statement in the XSLT:

<ns13:Insert>
  <ns13:Rows>
  <xsl:for-each select="*/*[local-name()='author']/*[local-name()='assignedAuthor']/*[local-name()='id']">
   <xsl:if test="string(../*[local-name()='id']/@root)='2.16.840.1.113883.4.6'">
      <ns13:NPI>
         <xsl:value-of select="./@extension" />
      </ns13:NPI>
    </xsl:if>
  </xsl:for-each>
  </ns13:Rows>
</ns13:Insert>

I get the following result (NPI doesn't show up because for some reason the if statement isn't evaluating to true and I can't figure out what I am doing wrong):

<ns13:Insert>
  <ns13:Rows>
  </ns13:Rows>
</ns13:Insert>

The XML is actually way more complex than this and there is too much to link here but this is the format of this one specific component section (minus the data that isn't pertinent to this question). The XSLT is also a lot more complex as well but it's just this one problem I am having. Any help would be appreciated.


Solution

  • When you do:

    <xsl:if test="string(../*[local-name()='id']/@root)='2.16.840.1.113883.4.6'">
    

    the string() is giving you the @root attribute value of the first id element. (In XSLT 2.0, it would be the @root values for all id elements.) This means you are doing this comparison:

    "1.2.840.113619.21.1.4780296594025264329.2.2" = "2.16.840.1.113883.4.6"
    

    which is false.

    Your context is already id, so just test the value of @root...

    <xsl:if test="@root='2.16.840.1.113883.4.6'">
    

    Also, unless there is a good reason (like you don't know what the namespace uri is going to be), it would be a lot cleaner to declare your namespace and use a prefix in your xpaths instead of using local-name().