如何匹配前一个兄弟的模板?

时间:2016-04-28 12:31:14

标签: xslt

我有这个XML

<math>
 <mrow>
  <mi>XY</mi>
  <mrow>
   <mrow>
    <mo>(</mo>
    <mrow>
     <mfrac>
      <mn>5</mn>
      <mrow>
       <mn>10</mn>
      </mrow>
     </mfrac>
    </mrow>
    <mo>)</mo>
   </mrow>
  </mrow>
  <msup>
   <mn>2</mn>
  </msup>
 </mrow>
</math>
<br/>
<math>
 <mrow>
  <mi>x</mi>
  <msub>
   <mn>1</mn>
  </msub>
  <msup>
   <mn>2</mn>
  </msup>
 </mrow>
</math>

以下XSL执行近似身份转换:它复制了所有内容,但它对msub元素和msup元素进行了特殊处理。如果我们同时拥有msubmsup,我们希望生成一个msupsub元素及其中的两个元素(以及前面的元素,它是子的基础) - 和上标)。如果我们只有一个,那么我们会生成一个msubmsup,但会将前一个兄弟作为第一个孩子。

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" encoding="UTF-8" indent="yes" />

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="msup">
    <xsl:choose>
      <xsl:when test="preceding-sibling::msub">
        <msubsup>
          <xsl:apply-templates 
            select="preceding-sibling::*[2]" />
          <xsl:apply-templates 
            select="preceding-sibling::msub[1]/child::*" />
          <xsl:apply-templates />
        </msubsup>
      </xsl:when>
      <xsl:when test="following-sibling::msub">

      </xsl:when>
      <xsl:otherwise>
        <msup>
          <xsl:apply-templates 
            select="preceding-sibling::*[1]" />
          <xsl:apply-templates />
        </msup>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="msub">
    <xsl:choose>
      <xsl:when test="preceding-sibling::msup">
        <msupsub>
          <xsl:apply-templates 
            select="preceding-sibling::*[2]" />
          <xsl:apply-templates 
            select="preceding-sibling::msup[1]/child::*" />
          <xsl:apply-templates />
        </msupsub>
      </xsl:when>
      <xsl:when test="following-sibling::msup">

      </xsl:when>
      <xsl:otherwise>
        <msub>
          <xsl:apply-templates 
            select="preceding-sibling::*[1]" />
          <xsl:apply-templates />
        </msub>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

我目前得到的输出是(大致):

<xml>
  <math display="block">
    <mrow>
      <mi>lakshmi</mi>
      <mrow>
        <mrow>
          <mo>(</mo>
          <mrow>
            <mfrac>
              <mn>5</mn>
              <mrow>
                <mn>10</mn>
              </mrow>
            </mfrac>
          </mrow>
          <mo>)</mo>
        </mrow>
      </mrow>
      <msup>
        <mrow>
          <mrow>
            <mo>(</mo>
            <mrow>
              <mfrac>
                <mn>5</mn>
                <mrow>
                  <mn>10</mn>
                </mrow>
              </mfrac>
            </mrow>
            <mo>)</mo>
          </mrow>
        </mrow>
        <mn>2</mn>
      </msup>
    </mrow>
    </math><br><math display="block">
    <mrow>
      <mi>x</mi>
      <msubsup>
        <mi>x</mi>
        <mn>1</mn>
        <mn>2</mn>
      </msubsup>
    </mrow>
  </math>
</xml>

但是在上面的输出中,紧接在下标和/或上标之前的元素(第一个数学表达式中的嵌套mrow,第二个中的mi)正在通过 之前的和下标(和/或上标)中的。

我们希望排除前面的兄弟&#39; msubsup&#39;和&#39; msup&#39;。也就是说,我们需要这样的输出,而不是上面显示的内容:

<xml>
  <math display="block">
    <mrow>
      <mi>lakshmi</mi>
      <msup>
        <mrow>
          <mrow>
            <mo>(</mo>
            <mrow>
              <mfrac>
                <mn>5</mn>
                <mrow>
                  <mn>10</mn>
                </mrow>
              </mfrac>
            </mrow>
            <mo>)</mo>
          </mrow>
        </mrow>
        <mn>2</mn>
      </msup>
    </mrow>
    </math><br><math display="block">
    <mrow>
      <msubsup>
        <mi>x</mi>
        <mn>1</mn>
        <mn>2</mn>
      </msubsup>
    </mrow>
  </math>
</xml>

我想知道如何匹配模板中特定的前一个兄弟。 如果有可能澄清。 谢谢你的进步。

1 个答案:

答案 0 :(得分:0)

我认为你有几个问题。

  • 我猜你真的只想合并相邻的msubmsup,而不是非相邻的对。

    因此msub模板中的第一个测试不应该是

    preceding-sibling::msub
    

    preceding-sibling::*[1]/self::msub
    
  • 如果您打算从这个不太完整的MathML输入中生成MathML(并且看起来确实好像在尝试),那么您不需要名为msupsub的元素,而是一个名为msubsup的元素<template match="msup" priority="10"> ... </> <template match="msup [preceding-sibling::*[1]/self::msub]" priority="20"> ... </> <template match="msup [following-sibling::*[1]/self::msub]" priority="20"/> <template match="msub" priority="10"> ... </> <template match="msub [preceding-sibling::*[1]/self::msup]" priority="20"> ... </> <template match="msub [following-sibling::*[1]/self::msup]" priority="20"/>

现在针对您在问题中提出的问题:如何保持下标和/或上标的基数出现两次?

如果是我,我会先将现有的两个模板(每个模板都有三个选择)分成六个模板,这样每个模板都会(更多)缩短,我会添加明确的优先级以允许我保持匹配模式简单:

mi

这至少对我来说有两件事。首先,如果它看到一个名为msubmsupmsubmsup的兄弟姐妹序列,很容易看到此代码不知道该怎么办, mi,或msubmsub<template match="*[not(self::msub or self::msup)] [following-sibling::*[1][self::msub or self::msup]"/> 。如果两者都保证不会发生,并且您可以信任该保证,则无需知道。 (真的吗?你可以相信你的上游数据制作人吗?感觉幸运吗?)

其次,它构成了大多数但不是全部的元素类型列表,这些元素不应该简单地通过样式表开头的默认标识转换模板复制到输出中。我们有单独出现的上标和下标,或者作为一对中的第一个出现的上标和下标,或者作为一对中的第二个出现的上标和下标。样式表中没有的是基本元素的模板,这些元素出现在下标或上标之前。

添加它,你就完成了。

setTimeout