tags:

views:

80

answers:

1

I currently am using two stylesheets to get my intended output. The first stylesheet (pass1.xsl) does the real work, and the second stylesheet (pass2.xsl) removes duplicates while providing minor formatting updates.

My question is whether I can perform both actions within a single stylesheet.
When I'm looking at the content, I don't get the impression I can via xsl:functions because both stylesheets contain template matches that would conflict if I copy/pasted from the second into the first. IE:

pass1.xsl:

<xsl:template match="xs:complexType">
  <xsl:param name="prefix" />    
  <xs:complexType name="{my:updateName($prefix, @name)}">

    <!-- insert xs:sequence ONLY if the child is NOT xs:complexContent -->
    <xsl:choose>
      <xsl:when test="*[name()='xs:complexContent']">
        <xsl:apply-templates select="node()" />
      </xsl:when>
      <xsl:otherwise>
        <xs:sequence>
          <xsl:apply-templates select="node()" />
        </xs:sequence>     
      </xsl:otherwise>
    </xsl:choose>
  </xs:complexType>
  <xsl:apply-templates select=".//xs:element" />
</xsl:template>

pass2.xsl:

<xsl:template match="xs:complexType">
  <xsl:copy>
    <xsl:apply-templates select="*|@*"/>
  </xsl:copy>
</xsl:template>

To reiterate - the goal is to run only one stylesheet to produce the final result. It's not a hardship to run two, but it'd be nice not to have to. Am I looking at copy/pasting into the original & making it work, or are imports/includes what I should be looking at? I'd prefer to only have one stylesheet file - to minimize the chance of someone mistakenly deleting a supporting file.

+1  A: 

You should use different modes for templates (this will require adding mode attribute to all xsl:template and xsl:apply-templates statements). Then your template for the root node in default mode would first fire off the root template in first mode, and then pass the result of that to the root template in the second mode. For this, you will need the ability to treat a result tree fragment (which is what element constructors produce) as a node-set (which is what you can apply templates to and otherwise query via XPath) - there's no standard way to do this, but exsl:node-set is a de facto standard for that (note that the full list of processors supporting it is larger than what's on that page - for example, .NET XslCompiledTransform supports it). So:

<xsl:template match="/">
   <xsl:variable name="round1-output">
     <xsl:apply-templates select="/" mode="round1" />
   </xsl:variable>
   <xsl:apply-templates select="exsl:node-set($round1-output)" mode="round2" />
</xsl:template>

<xsl:template match="/" mode="round1">
   ...
   <xsl:apply-templates mode="round1" />
   ...
</xsl:template>

<xsl:template match="/" mode="round2">
   ...
   <xsl:apply-templates mode="round2" />
   ...
</xsl:template>

...

<xsl:template match="xs:complexType" mode="round1">
  <xsl:param name="prefix" />           
  <xs:complexType name="{my:updateName($prefix, @name)}">
    <!-- insert xs:sequence ONLY if the child is NOT xs:complexContent -->
    <xsl:choose>
      <xsl:when test="*[name()='xs:complexContent']">
        <xsl:apply-templates select="node()" mode="round1"/>
      </xsl:when>
      <xsl:otherwise>
        <xs:sequence>
          <xsl:apply-templates select="node()" mode="round1"/>
        </xs:sequence>                          
      </xsl:otherwise>
    </xsl:choose>
  </xs:complexType>
  <xsl:apply-templates select=".//xs:element" mode="round1"/>
</xsl:template>

<xsl:template match="xs:complexType" mode="round2">
  <xsl:copy>
    <xsl:apply-templates select="*|@*" mode="round2"/>
  </xsl:copy>
</xsl:template>
Pavel Minaev