samedi 1 août 2015

How to process elements only if they're _not_ followed by a specific element

I have an XML like this:

<?xml version="1.0"?>
<root>
  <mtef>
    <slot>
      <options>0</options>
      <char>
        <typeface>2</typeface>
        <mt_code_value>0x0028</mt_code_value>
      </char>
      <char>
        <typeface>3</typeface>
        <mt_code_value>0x0062</mt_code_value>
      </char>
      <char>
        <typeface>2</typeface>
        <mt_code_value>0x0029</mt_code_value>
      </char>
      <tmpl>
        <selector>tmSUP</selector>
        <template_specific_options>0</template_specific_options>
        <sub/>
        <slot>
          <options>1</options>
        </slot>
        <slot>
          <options>0</options>
          <char>
            <typeface>3</typeface>
            <mt_code_value>0x0063</mt_code_value>
          </char>
          <end/>
        </slot>
        <end/>
      </tmpl>
      <end/>
    </slot>
    <end/>
  </mtef>
</root>

If the tmpl element with the tmSUP selector is preceded by a char with a mt_code_value of 0x0029 (HTML entity for right parenthesis), then the processing of this tmpl element must find the opening, left parenthesis, and use those in-between char elements in its template.

The issue I'm having is with the double processing of char elements, first by their own template, then by the tmpl[selector='tmSUP'] template. How do I prevent char elements from being processed when a succeeding tmpl element is following a char with the mt_code_value of 0x0029?

My stylesheet looks like this currently:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://ift.tt/tCZ8VR"
    xmlns:xs="http://ift.tt/tphNwY"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:template match="/">
        <root>
           <xsl:apply-templates select=".//mtef" />
        </root>
    </xsl:template>

    <xsl:template match="mtef">
        <math>
            <xsl:apply-templates select="slot"/>
        </math>
    </xsl:template>

    <xsl:template match="slot">
        <mrow>
            <xsl:apply-templates/>
        </mrow>
    </xsl:template>

    <xsl:template match="tmpl[selector = 'tmSUP']">
        <msup>
        <mrow>
            <xsl:choose>
                <!-- Closing bracket -->
                <xsl:when test="preceding-sibling::char[1]/mt_code_value = '0x0029'">
                    <xsl:for-each select="preceding-sibling::*">
                        <xsl:sort select="position()" data-type="number" order="ascending"/>
                        <xsl:apply-templates select="."/>
                    </xsl:for-each>
                </xsl:when>
            </xsl:choose>            
        </mrow>
            <xsl:apply-templates select="slot[2]"/>
        </msup>
     </xsl:template>

    <xsl:template match="char[typeface = '2']">
        <mn>
            <xsl:text disable-output-escaping="yes">&amp;#</xsl:text>
            <xsl:value-of select="substring(mt_code_value/text(), 2)"/>
            <xsl:text>;</xsl:text>
        </mn>
    </xsl:template>

    <xsl:template match="char[typeface = '3']">
        <mi>
            <xsl:text disable-output-escaping="yes">&amp;#</xsl:text>
            <xsl:value-of select="substring(mt_code_value/text(), 2)"/>
            <xsl:text>;</xsl:text>
        </mi>
    </xsl:template>

    <xsl:template match="*" />

</xsl:stylesheet>

Which results in this output:

<?xml version="1.0" encoding="UTF-8"?><root>
  <math>
    <mrow>  
      <mn>&#x0028;</mn>
      <mi>&#x0061;</mi>
      <mo>&#x2212;</mo>
      <mi>&#x0062;</mi>
      <mn>&#x0029;</mn>
      <msup>
        <mrow>
          <mn>&#x0028;</mn><mi>&#x0061;</mi><mo>&#x2212;</mo><mi>&#x0062;</mi><mn>&#x0029;</mn>
        </mrow>
        <mrow>  
          <mi>&#x0063;</mi>
        </mrow>
      </msup>
    </mrow>
  </math>
</root>

Notice how some elements appear twice. What is a general approach to solving this kind of conditional "look-ahead" processing with XSLT?

Aucun commentaire:

Enregistrer un commentaire