-1

My question is based on Tom Winter's answer (https://stackoverflow.com/a/17728489/3574368) in the following post: How to call named templates based on a variable? I cannot add a comment to the original post and am posting a follow up question.

I am attempting to call a named template using the same method described in the answer and have been unsuccessful.

The base XML comes in from an external source formatted as (excerpt):

<DRU1>
...
</DRU1>
<SIG1>
...
</SIG1>
<SIG2>
...
</SIG2>
...
<SIG20>
...
</SIG20>

A template exists for each, stored in separate xslt files, with names SIG1, SIG2 and so on.

A main template was constructed to call these other templates based on the existence of the elements. I haven't included the whole thing, just the top section that attempts to call the template by a named variable.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns="http://www.ncpdp.org/schema/SCRIPT">

  <xsl:output method="xml" indent="yes"/>

  <!-- Call Template case -->
  <xsl:include href="./DRU1aXML.xslt" />
  <xsl:include href="./DRU2aXML.xslt" />
  <xsl:include href="./SIG1XML.xslt" />
  <xsl:include href="./SIG2XML.xslt" />
  <xsl:include href="./SIG3XML.xslt" />
  <xsl:include href="./SIG4XML.xslt" />
  <xsl:include href="./SIG5XML.xslt" />
  <xsl:include href="./SIG6XML.xslt" />
  <xsl:include href="./SIG7XML.xslt" />
  <xsl:include href="./SIG8XML.xslt" />
  <xsl:include href="./SIG9XML.xslt" />
  <xsl:include href="./SIG10XML.xslt" />

  <xsl:variable name="templates">
    <templates><SIG1/><SIG2/><SIG3/><SIG4/><SIG5/><SIG6/><SIG7/><SIG8/><SIG9/><SIG10/>
    </templates>
  </xsl:variable>

  <xsl:template name="DRUMAIN" match="*[(starts-with(.,'DRU') or starts-with(.,'SIG'))]">

    <xsl:choose>      <!-- Prescribed -->
      <xsl:when test="DRU1/DRU1_010/DRU1_010_01='P'">
        <MedicationPrescribed>
          <xsl:call-template name="DRU1a"/>

          <xsl:for-each select="/*/*[starts-with(name(), 'SIG')]">
            <xsl:variable name="template-name" select="concat('SIG', position())"/>
            <xsl:apply-templates select="msxsl:node-set($templates)/*/*[local-name() = $template-name]" mode="call-template" />
          </xsl:for-each>

          <!--<xsl:if test="SIG1/SIG1_010">
            <xsl:call-template name="SIG1"/>
          </xsl:if>-->
        </MedicationPrescribed>
      </xsl:when>
...

The template never gets called unless I call it explicitly by name (see commented out section). Is it really necessary to list this 20 times, explicitly using the name of the template (SIG1, SIG2, etc)? Or can the template be called this way using position() to build the template name?

UPDATE: Added SIG1 template as requested

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns="http://www.ncpdp.org/schema/SCRIPT">

  <xsl:output method="xml" indent="yes"/>
  <xsl:template name="SIG1" match="SIG1">
    <StructuredSIG>
      <RepeatingSIG>
        <SigSequencePositionNumber>
          <xsl:value-of select="SIG1/SIG1_010/SIG1_010_01"/>
        </SigSequencePositionNumber>
        <MultipleSigModifier>
          <xsl:value-of select="SIG1/SIG1_010/SIG1_010_02"/>
        </MultipleSigModifier>
      </RepeatingSIG>

      <CodeSystem>
        <SNOMEDVersion>
          <xsl:value-of select="SIG1/SIG1_020/SIG1_020_01"/>
        </SNOMEDVersion>
        <FMTVersion>
          <xsl:value-of select="SIG1/SIG1_020/SIG1_020_02"/>
        </FMTVersion>
      </CodeSystem>

      <FreeText>
        <SigFreeTextStringIndicator>
          <xsl:value-of select="SIG1/SIG1_030/SIG1_030_01"/>
        </SigFreeTextStringIndicator>
        <SigFreeText>
          <xsl:value-of select="SIG1/SIG1_030/SIG1_030_02"/>
        </SigFreeText>
      </FreeText>

      <Dose>
        <DoseCompositeIndicator>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_01"/>
        </DoseCompositeIndicator>
        <DoseDeliveryMethodText>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_02"/>
        </DoseDeliveryMethodText>
        <DoseDeliveryMethodCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_03"/>
        </DoseDeliveryMethodCodeQualifier>
        <DoseDeliveryMethodCode>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_04"/>
        </DoseDeliveryMethodCode>
        <DoseDeliveryMethodModifierText>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_05"/>
        </DoseDeliveryMethodModifierText>
        <DoseDeliveryMethodModifierCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_06"/>
        </DoseDeliveryMethodModifierCodeQualifier>
        <DoseDeliveryMethodModifierCode>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_07"/>
        </DoseDeliveryMethodModifierCode>
        <DoseQuantity>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_08"/>
        </DoseQuantity>
        <DoseFormText>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_09"/>
        </DoseFormText>
        <DoseFormCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_10"/>
        </DoseFormCodeQualifier>
        <DoseFormCode>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_11"/>
        </DoseFormCode>
        <DoseRangeModifier>
          <xsl:value-of select="SIG1/SIG1_040/SIG1_040_12"/>
        </DoseRangeModifier>
      </Dose>

      <DoseCalculation>
        <DosingBasisNumericValue>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_01"/>
        </DosingBasisNumericValue>
        <DosingBasisUnitofMeasureText>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_02"/>
        </DosingBasisUnitofMeasureText>
        <DosingBasisUnitofMeasureCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_03"/>
        </DosingBasisUnitofMeasureCodeQualifier>
        <DosingBasisUnitofMeasureCode>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_04"/>
        </DosingBasisUnitofMeasureCode>
        <BodyMetricQualifier>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_05"/>
        </BodyMetricQualifier>
        <BodyMetricValue>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_06"/>
        </BodyMetricValue>
        <CalculatedDoseNumeric>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_07"/>
        </CalculatedDoseNumeric>
        <CalculatedDoseUnitofMeasureText>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_08"/>
        </CalculatedDoseUnitofMeasureText>
        <CalculatedDoseUnitofMeasureCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_09"/>
        </CalculatedDoseUnitofMeasureCodeQualifier>
        <CalculatedDoseUnitofMeasureCode>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_10"/>
        </CalculatedDoseUnitofMeasureCode>
        <DosingBasisRangeModifier>
          <xsl:value-of select="SIG1/SIG1_050/SIG1_050_11"/>
        </DosingBasisRangeModifier>
      </DoseCalculation>

      <Vehicle>
        <VehicleName>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_01"/>
        </VehicleName>
        <VehicleNameCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_02"/>
        </VehicleNameCodeQualifier>
        <VehicleNameCode>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_03"/>
        </VehicleNameCode>
        <VehicleQuantity>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_04"/>
        </VehicleQuantity>
        <VehicleUnitOfMeasureText>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_05"/>
        </VehicleUnitOfMeasureText>
        <VehicleUnitOfMeasureCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_06"/>
        </VehicleUnitOfMeasureCodeQualifier>
        <VehicleUnitOfMeasureCode>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_07"/>
        </VehicleUnitOfMeasureCode>
        <MultipleVehicleModifier>
          <xsl:value-of select="SIG1/SIG1_060/SIG1_060_08"/>
        </MultipleVehicleModifier>
      </Vehicle>

      <RouteofAdministration>
        <RouteofAdministrationText>
          <xsl:value-of select="SIG1/SIG1_070/SIG1_070_01"/>
        </RouteofAdministrationText>
        <RouteofAdministrationCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_070/SIG1_070_02"/>
        </RouteofAdministrationCodeQualifier>
        <RouteofAdministrationCode>
          <xsl:value-of select="SIG1/SIG1_070/SIG1_070_03"/>
        </RouteofAdministrationCode>
        <MultipleRouteofAdministrationModifier>
          <xsl:value-of select="SIG1/SIG1_070/SIG1_070_04"/>
        </MultipleRouteofAdministrationModifier>
      </RouteofAdministration>

      <SiteofAdministration>
        <SiteofAdministrationText>
          <xsl:value-of select="SIG1/SIG1_080/SIG1_080_01"/>
        </SiteofAdministrationText>
        <SiteofAdministrationCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_080/SIG1_080_02"/>
        </SiteofAdministrationCodeQualifier>
        <SiteofAdministrationCode>
          <xsl:value-of select="SIG1/SIG1_080/SIG1_080_03"/>
        </SiteofAdministrationCode>
        <MultipleAdministrationTimingModifier>
          <xsl:value-of select="SIG1/SIG1_080/SIG1_080_04"/>
        </MultipleAdministrationTimingModifier>
      </SiteofAdministration>

      <Timing>
        <AdministrationTimingText>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_01"/>
        </AdministrationTimingText>
        <AdministrationTimingCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_02"/>
        </AdministrationTimingCodeQualifier>
        <AdministrationTimingCode>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_03"/>
        </AdministrationTimingCode>
        <MultipleAdministrationTimingModifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_04"/>
        </MultipleAdministrationTimingModifier>
        <RateofAdministration>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_05"/>
        </RateofAdministration>
        <RateUnitofMeasureText>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_06"/>
        </RateUnitofMeasureText>
        <RateUnitofMeasureCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_07"/>
        </RateUnitofMeasureCodeQualifier>
        <RateUnitofMeasureCode>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_08"/>
        </RateUnitofMeasureCode>
        <TimePeriodBasisText>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_09"/>
        </TimePeriodBasisText>
        <TimePeriodBasisCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_10"/>
        </TimePeriodBasisCodeQualifier>
        <TimePeriodBasisCode>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_11"/>
        </TimePeriodBasisCode>
        <FrequencyNumericValue>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_12"/>
        </FrequencyNumericValue>
        <FrequencyUnitsText>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_13"/>
        </FrequencyUnitsText>
        <FrequencyUnitsCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_14"/>
        </FrequencyUnitsCodeQualifier>
        <FrequencyUnitsCode>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_15"/>
        </FrequencyUnitsCode>
        <VariableFrequencyModifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_16"/>
        </VariableFrequencyModifier>
        <IntervalNumericValue>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_17"/>
        </IntervalNumericValue>
        <IntervalUnitsText>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_18"/>
        </IntervalUnitsText>
        <IntervalUnitsCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_19"/>
        </IntervalUnitsCodeQualifier>
        <IntervalUnitsCode>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_20"/>
        </IntervalUnitsCode>
        <VariableIntervalModifier>
          <xsl:value-of select="SIG1/SIG1_090/SIG1_090_21"/>
        </VariableIntervalModifier>
      </Timing>

      <Duration>
        <DurationNumericValue>
          <xsl:value-of select="SIG1/SIG1_100/SIG1_100_01"/>
        </DurationNumericValue>
        <DurationText>
          <xsl:value-of select="SIG1/SIG1_100/SIG1_100_02"/>
        </DurationText>
        <DurationTextCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_100/SIG1_100_03"/>
        </DurationTextCodeQualifier>
        <DurationTextCode>
          <xsl:value-of select="SIG1/SIG1_100/SIG1_100_04"/>
        </DurationTextCode>
      </Duration>

      <MaximumDoseRestriction>
        <MaximumDoseRestrictionNumericValue>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_01"/>
        </MaximumDoseRestrictionNumericValue>
        <MaximumDoseRestrictionUnitsText>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_02"/>
        </MaximumDoseRestrictionUnitsText>
        <MaximumDoseRestrictionCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_03"/>
        </MaximumDoseRestrictionCodeQualifier>
        <MaximumDoseRestrictionUnitsCode>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_04"/>
        </MaximumDoseRestrictionUnitsCode>
        <MaximumDoseRestrictionVariableNumericValue>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_05"/>
        </MaximumDoseRestrictionVariableNumericValue>
        <MaximumDoseRestrictionVariableUnitsText>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_06"/>
        </MaximumDoseRestrictionVariableUnitsText>
        <MaximumDoseRestrictionVariableUnitsCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_07"/>
        </MaximumDoseRestrictionVariableUnitsCodeQualifier>
        <MaximumDoseRestrictionVariableUnitsCode>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_08"/>
        </MaximumDoseRestrictionVariableUnitsCode>
        <MaximumDoseRestrictionVariableDurationModifier>
          <xsl:value-of select="SIG1/SIG1_110/SIG1_110_09"/>
        </MaximumDoseRestrictionVariableDurationModifier>
      </MaximumDoseRestriction>

      <Indication>
        <IndicationPrecursorText>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_01"/>
        </IndicationPrecursorText>
        <IndicationPrecursorCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_02"/>
        </IndicationPrecursorCodeQualifier>
        <IndicationPrecursorCode>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_03"/>
        </IndicationPrecursorCode>
        <IndicationText>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_04"/>
        </IndicationText>
        <IndicationTextCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_05"/>
        </IndicationTextCodeQualifier>
        <IndicationTextCode>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_06"/>
        </IndicationTextCode>
        <IndicationValueText>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_07"/>
        </IndicationValueText>
        <IndicationValueUnit>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_08"/>
        </IndicationValueUnit>
        <IndicationValueUnitofMeasureText>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_09"/>
        </IndicationValueUnitofMeasureText>
        <IndicationValueUnitofMeasureCodeQualifier>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_10"/>
        </IndicationValueUnitofMeasureCodeQualifier>
        <IndicationValueUnitofMeasureCode>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_11"/>
        </IndicationValueUnitofMeasureCode>
        <IndicationVariableModifier>
          <xsl:value-of select="SIG1/SIG1_120/SIG1_120_12"/>
        </IndicationVariableModifier>
      </Indication>

      <Stop>
        <StopIndicator>
          <xsl:value-of select="SIG1/SIG1_130/SIG1_130_01"/>
        </StopIndicator>
      </Stop>

    </StructuredSIG>

    </xsl:template>
</xsl:stylesheet>  
Community
  • 1
  • 1
mslissap
  • 413
  • 4
  • 14
  • IMHO, using `xsl:choose` (and nothing else) to select the template (or rather the corresponding `xsl:call-template` instruction) would be the most straightforward and easiest to maintain solution here. I would post this as an answer, but your example does provide enough code to demonstrate. – michael.hor257k Feb 20 '15 at 21:28
  • Would it be possible to show at least on of the other templates in your include files. For example, the one for `SIG1` perhaps? Thanks! – Tim C Feb 21 '15 at 08:48
  • With the input having elements named `SIG1`, `SIG2`, I would expect the easiest approach to process them to simply have templates matching them with e.g. `...`, `...` instead of using named templates. That way an `apply-templates` would suffice to select a matching template. – Martin Honnen Feb 21 '15 at 09:38
  • @Tim C - I added the SIG1 template as you requested. – mslissap Feb 23 '15 at 13:10
  • @Martin Honnen - are you saying if I use match="SIG1" (which I am) that I don't need to call the template by name, just apply it? – mslissap Feb 23 '15 at 13:11

1 Answers1

1

The problem is the mismatched mode attributes - your SIG1 template does not have a mode but your apply-templates does. When you use mode on apply-templates, only template rules that declare the same mode are considered as potential matches.

But as Martin suggests in the comments, since there appears to be a direct correlation between the name of the node you're looking at and the name of the template you want to apply, you can just use normal apply-templates and let the template matcher take care of selecting the right template:

    <MedicationPrescribed>
      <xsl:call-template name="DRU1a"/>

      <xsl:apply-templates select="/*/*[starts-with(name(), 'SIG')]"/>

The SIG1 element will fire the template with match="SIG1", etc. etc.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Thank you - I was making this a lot harder than it needed to be. – mslissap Feb 23 '15 at 13:47
  • @mslissap indeed. If you're used to more procedural or OO languages then moving to XSLT requires quite a change of mindset. The key thing the template matching mechanism buys you is that it allows you to separate the matter of _which_ nodes you want to process from _how_ you process each one. Some transformations are much easier to express in terms of one and some in terms of the other. – Ian Roberts Feb 23 '15 at 14:00