如何访问具有相同名称和格式的嵌套子元素

时间:2017-06-05 09:37:18

标签: xml xslt xslt-2.0

请建议,如何到达内部的mrow / mo包含大括号。

在给定的样本中,当mrow(如果它的第一个和最后一个孩子应该是带有大括号的'MO')时,第一级括号被转换为'MFENCED'。但无法修改二级括号,其中那些也是'MFRAC'作为后代。模板匹配应来自'MROW'(如给定的)。

XML输入:

<article>
<body>
<math id="m1">
    <mrow>
      <mo>(</mo><!--first level braces open-->
        <mi>u</mi>
        <mo>+</mo>
        <mi>g</mi>
        <mi>=</mi>
        <mrow>
            <mo>(</mo><!--second level braces open-->
            <mfrac>
                <mrow><mn>1</mn></mrow>
                <mrow><mn>2</mn></mrow>
            </mfrac>
            <mo>)</mo><!--second level braces close-->
        </mrow>
      <mo>)</mo><!--first level braces close-->
    </mrow>
</math>

<math id="m2">
    <mrow>
        <mo>(</mo>
            <mrow>
                <mfrac>
                    <mn>8</mn>
                    <mn>9</mn>
                </mfrac>
            </mrow>
        <mo>)</mo>
    </mrow>
</math>
</body>
</article>

XSLT 2.0:

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

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

<xsl:template match="mrow[matches(child::*[1][name()='mo'], '^(\(|\[|\{)$')]
                            [matches(child::*[position()=last()][name()='mo'], '^(\)|\]|\})$')]">
    <xsl:choose>
        <xsl:when test="descendant::mfrac">
            <xsl:copy>
                <xsl:element name="mfenced">
                    <xsl:attribute name="open"><xsl:value-of select="child::*[1][name()='mo']"/></xsl:attribute>
                    <xsl:attribute name="close"><xsl:value-of select="child::*[position()=last()][name()='mo']"/></xsl:attribute>
                        <xsl:for-each select="*">
                            <xsl:if test="position()=1"/>
                            <xsl:if test="not(position()=1) and not(position()=last())">
                                <xsl:copy><xsl:apply-templates select="@* | node()"/></xsl:copy>
                            </xsl:if>
                            <xsl:if test="position()=last()"/>
                        </xsl:for-each>
                </xsl:element>
            </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy><xsl:apply-templates select="@* | node()"/></xsl:copy>
        </xsl:otherwise>
        </xsl:choose>
</xsl:template>
</xsl:stylesheet>

必填结果:

<article>
<body>
<math id="m1">
    <mrow>
        <mfenced open="(" close=")"><mi>u</mi><mo>+</mo><mi>g</mi><mi>=</mi>
            <mrow>
            <mfenced open="(" close=")"><!-- this node or modification required, because, within this MFRAC presents, then it should convert to 'MFENCED' -->
                <mfrac>
                    <mrow><mn>1</mn></mrow>
                    <mrow><mn>2</mn></mrow>
                </mfrac>
            </mfenced>
            </mrow>
        </mfenced>
    </mrow>
</math>

<math id="m2">
    <mrow>
        <mfenced open="(" close=")">
            <mrow>
                <mfrac>
                    <mn>8</mn>
                    <mn>9</mn>
                </mfrac>
            </mrow>
        </mfenced>
    </mrow>
</math>
</body>
</article>

1 个答案:

答案 0 :(得分:1)

我认为您可以使用xsl:for-each-group group-starting-with/group-ending-with,如下所示:

<?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:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="mrow[mo = '(']">
        <xsl:copy>
            <xsl:for-each-group select="*" group-starting-with="mo[. = '(']">
                <xsl:choose>
                    <xsl:when test="self::mo[. =  '(']">
                        <xsl:for-each-group select="current-group() except ." group-ending-with="mo[. = ')']">
                            <xsl:choose>
                                <xsl:when test="current-group()[last()][self::mo[. = ')']]">
                                    <mfenced open="(" close=")">
                                        <xsl:apply-templates select="current-group()[not(position() eq last())]"/>
                                    </mfenced>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:apply-templates select="current-group()"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:for-each-group>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

这给了

<?xml version="1.0" encoding="UTF-8"?>
<article>
   <body>
      <math id="m1">
         <mrow>
            <mfenced open="(" close=")">
               <mi>u</mi>
               <mo>+</mo>
               <mi>g</mi>
               <mi>=</mi>
               <mrow>
                  <mfenced open="(" close=")">
                     <mfrac>
                        <mrow>
                           <mn>1</mn>
                        </mrow>
                        <mrow>
                           <mn>2</mn>
                        </mrow>
                     </mfrac>
                  </mfenced>
               </mrow>
            </mfenced>
         </mrow>
      </math>
      <math id="m2">
         <mrow>
            <mfenced open="(" close=")">
               <mrow>
                  <mfrac>
                     <mn>8</mn>
                     <mn>9</mn>
                  </mfrac>
               </mrow>
            </mfenced>
         </mrow>
      </math>
   </body>
</article>