我有这样的XML:
<?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>
如果带有tmpl
选择器的tmSUP
元素前面有char
且mt_code_value
为0x0029(右括号的HTML实体),则处理此tmpl
元素必须找到左括号,并在其模板中使用中间char
元素。
我遇到的问题是char
元素的双重处理,首先是他们自己的模板,然后是tmpl[selector='tmSUP']
模板。当后续char
元素跟随tmpl
的{{1}}为0x0029时,如何防止char
元素被处理?
我的样式表目前看起来像这样:
mt_code_value
这导致此输出:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
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">&#</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">&#</xsl:text>
<xsl:value-of select="substring(mt_code_value/text(), 2)"/>
<xsl:text>;</xsl:text>
</mi>
</xsl:template>
<xsl:template match="*" />
</xsl:stylesheet>
注意一些元素如何出现两次。
所需的输出是:
<?xml version="1.0" encoding="UTF-8"?><root>
<math>
<mrow>
<mn>(</mn>
<mi>a</mi>
<mo>−</mo>
<mi>b</mi>
<mn>)</mn>
<msup>
<mrow>
<mn>(</mn><mi>a</mi><mo>−</mo><mi>b</mi><mn>)</mn>
</mrow>
<mrow>
<mi>c</mi>
</mrow>
</msup>
</mrow>
</math>
</root>
解决这种条件&#34;前瞻&#34;的一般方法是什么?使用XSLT进行处理?
答案 0 :(得分:1)
一种可能性是将tmpl
上的条件移出与tmpl
本身匹配的模板,并移至与slot
匹配的模板中。这样,如果条件为真,那么您只能选择tmpl
元素,而不能选择其他char
元素。
因此,与slot
匹配的模板如下所示:
<xsl:template match="slot">
<mrow>
<xsl:choose>
<xsl:when test="tmpl[selector = 'tmSUP'][preceding-sibling::char[1]/mt_code_value = '0x0029']">
<xsl:apply-templates select="tmpl" mode="sup" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</mrow>
</xsl:template>
在mode
上使用xsl:apply-templates
只是因为您可能需要在满足条件时使用tmpl
的单独模板。
试试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<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:choose>
<xsl:when test="tmpl[selector = 'tmSUP'][preceding-sibling::char[1]/mt_code_value = '0x0029']">
<xsl:apply-templates select="tmpl" mode="sup" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</mrow>
</xsl:template>
<xsl:template match="tmpl" mode="sup">
<msup>
<mrow>
<xsl:for-each select="preceding-sibling::*">
<xsl:sort select="position()" data-type="number" order="ascending"/>
<xsl:apply-templates select="."/>
</xsl:for-each>
</mrow>
<xsl:apply-templates select="slot[2]"/>
</msup>
</xsl:template>
<xsl:template match="char[typeface = '2']">
<mn>
<xsl:text disable-output-escaping="yes">&#</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">&#</xsl:text>
<xsl:value-of select="substring(mt_code_value/text(), 2)"/>
<xsl:text>;</xsl:text>
</mi>
</xsl:template>
<xsl:template match="*" />
</xsl:stylesheet>
我不确定这是否能为您提供所需的输出,但这可能是一个开始。
当您使用XSLT 2.0时,稍微不同的方法是使用xsl:for-each-group
和以tmpl
结尾的组。然后,您可以测试组中的最后一个元素是否与条件匹配,并相应地采取相应措施。
尝试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<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:for-each-group select="*" group-ending-with="tmpl">
<xsl:variable name="last" select="current-group()[last()]" />
<xsl:choose>
<xsl:when test="$last[self::tmpl][selector = 'tmSUP'][preceding-sibling::char[1]/mt_code_value = '0x0029']">
<xsl:apply-templates select="$last" mode="sup" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</mrow>
</xsl:template>
<xsl:template match="tmpl" mode="sup">
<msup>
<mrow>
<xsl:for-each select="current-group() except tmpl">
<xsl:sort select="position()" data-type="number" order="ascending"/>
<xsl:apply-templates select="."/>
</xsl:for-each>
</mrow>
<xsl:apply-templates select="slot[2]"/>
</msup>
</xsl:template>
<xsl:template match="char[typeface = '2']">
<mn>
<xsl:text disable-output-escaping="yes">&#</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">&#</xsl:text>
<xsl:value-of select="substring(mt_code_value/text(), 2)"/>
<xsl:text>;</xsl:text>
</mi>
</xsl:template>
<xsl:template match="*" />
</xsl:stylesheet>