【问题标题】:How to identify particular descendant element found under first-or-second descendant of another element如何识别在另一个元素的第一个或第二个后代下找到的特定后代元素
【发布时间】:2017-03-28 05:31:51
【问题描述】:

请建议识别 MFENCED,它是否将 MFRAC 作为 MSUB 的后代。

这里提到的一些场景如下拉伸MFENCED(插入一个属性):

  • 如果找到 MFRAC 并且不在 MSUB 下,则属性 STRETCH
    MFENCED 是必需的。
  • 如果发现 MFRAC 是 MFENCED 的后代,并且 在 MSUB 的 FIRST-CHILD-DESCENDANT 下,则需要 STRETCH。
  • 在来自输入 xml 的第三个 MATH 中,第二个 MFENCED 需要 STRETCH,即使是 MSUB 的第二个子后代的 MFRAC 后代,但在该 MFENCED 中,MFRAC 没有 MSUB 作为其祖先。

新增进一步说明:

如果MFENCED 在(来自 (this) 的后代存在 MFENCED)下找到任何 MFRAC,则 MFENCED 可以伸展,而 MFENCE/祖先不应伸展,因为相对于主 MFENCE , FRAC 在 sub 的第二个子后裔下找到。如果不清楚,我会给出进一步的解释。

输入 XML:

<article>

<math>
    <mrow>
        <mfenced open="(" close=")">
            <!--stretch required -->
            <mrow>
                <mrow><mn>99999</mn></mrow>
                    <mrow>
                            <mrow><mn>9999</mn></mrow>
                            <mrow>
                                <mfenced open="(" close=")">
                                    <!--stretch required -->
                                    <mrow>
                                        <mfrac><mi>a</mi><mi>b</mi></mfrac>
                                    </mrow>
                                </mfenced>
                            </mrow>
                    </mrow>
                </mrow>
        </mfenced>
    </mrow>
</math>

<math>
    <mrow>
        <mfenced open="(" close=")"><!--Stretch  required, bcs descendant Frac, found as first child of msub, if descendant mfrac, found under (descendant) second child of MSUB, then no need to stretch-->
            <mrow>
                <mrow><mn>99999</mn></mrow>
                    <mrow>
                        <msub>
                            <mrow>
                                <mfenced open="(" close=")"><!--Stretch required, because under this mfen, 'mfrac' found under first child of 'msub' -->
                                    <mrow>
                                        <mfrac><mi>a</mi><mi>b</mi></mfrac>
                                    </mrow>
                                </mfenced>
                            </mrow>
                            <mrow><mn>9999</mn></mrow>
                        </msub>
                    </mrow>
                </mrow>
        </mfenced>
    </mrow>
</math>


<math>
    <mrow>
        <mfenced open="(" close=")"><!-- this mfence, no need to stretch, because, descendant MFRAC found under second child-descendant of MSUB -->
            <mrow>
                <mrow><mn>99999</mn></mrow>
                    <mrow>
                        <msub>
                            <mrow><mn>9999</mn></mrow>
                            <mrow>
                                <mfenced open="(" close=")"><!--Stretch required, because under this mfen, 'mfrac' found (even MFRAC under 2nd child-descendant of MSUB, but under existing MFENCE, MFRAC is not having ancestor MSUB -->
                                    <mrow>
                                        <mfrac><mi>a</mi><mi>b</mi></mfrac>
                                    </mrow>
                                </mfenced>
                            </mrow>
                        </msub>
                    </mrow>
                </mrow>
        </mfenced>
    </mrow>
</math>
</article>

XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<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="mfenced">
    <xsl:variable name="varFrac">
        <xsl:for-each select="descendant::mfenced">
            <xsl:for-each select="descendant::*[name()='mfrac']">
                <xsl:choose>
                    <xsl:when  test="not(ancestor::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')]
                        [generate-id(ancestor::mmlmfenced[1])=generate-id(current()/ancestor::mmlmfenced[1])])">Yes2</xsl:when>
                    <xsl:when  test="(ancestor-or-self::*/parent::*[not(preceding-sibling::*)]/parent::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')]
                        [generate-id(ancestor::mmlmfenced[1])=generate-id(current()/ancestor::mmlmfenced[1])])">Yes21</xsl:when>
                </xsl:choose>
            </xsl:for-each>
        </xsl:for-each>

        <xsl:for-each select="descendant::*[name()='mfrac']">
            <xsl:choose>
                <xsl:when  test="not(ancestor::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')])">Yes1a</xsl:when>
                <xsl:when  test="(ancestor-or-self::*/parent::*[not(preceding-sibling::*)]/parent::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')])">Yes11a</xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:variable>

        <xsl:choose>
            <xsl:when test="contains($varFrac, 'Yes')">
                <xsl:copy>
                    <xsl:apply-templates select="@*"/>
                    <xsl:attribute name="stretchy">true</xsl:attribute>
                    <xsl:apply-templates select="node()"/>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
</xsl:template>

</xsl:stylesheet>

要求的结果:

<article>
<math>
  <mrow>
     <mfenced open="(" close=")" stretchy="true">
          <mrow>
           <mrow>
              <mn>99999</mn>
           </mrow>
           <mrow>
              <mrow>
                 <mn>9999</mn>
              </mrow>
              <mrow>
                 <mfenced open="(" close=")" stretchy="true">
                    <mrow>
                       <mfrac>
                          <mi>a</mi>
                          <mi>b</mi>
                       </mfrac>
                    </mrow>
                 </mfenced>
              </mrow>
           </mrow>
        </mrow>
     </mfenced>
  </mrow>
</math>

<math>
  <mrow>
     <mfenced open="(" close=")" stretchy="true">
        <mrow>
           <mrow>
              <mn>99999</mn>
           </mrow>
           <mrow>
              <msub>
                 <mrow>
                    <mfenced open="(" close=")" stretchy="true">
                        <mrow>
                          <mfrac>
                             <mi>a</mi>
                             <mi>b</mi>
                          </mfrac>
                       </mrow>
                    </mfenced>
                 </mrow>
                 <mrow>
                    <mn>9999</mn>
                 </mrow>
              </msub>
           </mrow>
        </mrow>
     </mfenced>
  </mrow>
</math>

<math>
  <mrow>
     <mfenced open="(" close=")">
        <mrow>
           <mrow>
              <mn>99999</mn>
           </mrow>
           <mrow>
              <msub>
                 <mrow>
                    <mn>9999</mn>
                 </mrow>
                 <mrow>
                    <mfenced open="(" close=")" stretchy="true"><!-- Here stretch required -->
                        <mrow>
                          <mfrac>
                             <mi>a</mi>
                             <mi>b</mi>
                          </mfrac>
                       </mrow>
                    </mfenced>
                 </mrow>
              </msub>
           </mrow>
        </mrow>
     </mfenced>
  </mrow>
</math>
</article>

【问题讨论】:

    标签: xslt xslt-2.0


    【解决方案1】:

    如果找到 MFRAC 并且不在 MSUB 下,则属性 STRETCH MFENCED 是必需的。

    <xsl:template match="mfenced[.//mfrac except .//msub//mfrac]">
      <xsl:copy>
       <xsl:attribute name="stretchy">true</xsl:attribute>
       <xsl:apply-templates select="@*, node()"/>
      </xsl:copy>
    </xsl:template>
    

    如果发现 MFRAC 是 MFENCED 及以下的后代 MSUB 的 FIRST-CHILD-DESCENDANT,然后需要 STRETCH。

    <xsl:template match="mfenced[.//msub/*[1]//mfrac]">
      <xsl:copy>
        <xsl:attribute name="stretchy">true</xsl:attribute>
        <xsl:apply-templates select="@*, node()"/>
      </xsl:copy>
    </xsl:template>
    

    在输入 xml 的第三个 MATH 中,第二个 MFENCED 需要 STRETCH,即使这样 MFRAC 的第二个子代 MSUB 的后裔,但在那个范围内 MFENCED,MFRAC 没有将 MSUB 作为其祖先。

    对不起,我听不懂你的英语。

    【讨论】:

    • 先生,最后一点,第二个 MFRAC 是 sub 的第二个孩子的后代。但是在 MFENCED 中(仅在这个 MFENCE 中)MFRAC 没有作为 MSUB 的祖先,这就是为什么我编写了一些 generate-id() 来检查那个 MFENCE。请提出建议。
    • 很快我会得到你的代码的帮助,先生,谢谢你的帮助。
    • 请注意,在 XSLT 2.0 中,您可以将 generate-id($X) = generate-id($Y) 重写为 $X is $Y,这大大简化了事情。
    • 非常感谢您的建议,但仍然无法延长第三次数学的第二次 MFENCED,再加上您的宝贵建议。
    【解决方案2】:

    新 XSLT:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <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="mfenced">
    
        <xsl:variable name="varFrac">
            <xsl:choose><!--to check only within MFENCED descendant is MFRAC -->
                <xsl:when test="descendant-or-self::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')]/*[not(preceding-sibling::*)]/descendant::mfrac">Yes1</xsl:when>
                <xsl:when test="descendant-or-self::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')]/*[(preceding-sibling::*)]/descendant::mfrac">No1</xsl:when>
                <xsl:when test="descendant-or-self::mfrac">Yes2</xsl:when>
            </xsl:choose>
            <!-- to check MFRAC found as online (first child-descendant of msub). -->
            <xsl:for-each select="descendant::*[name()='mfrac']">
                <xsl:choose>
                    <xsl:when  test="not(ancestor::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')])">Yes1a</xsl:when>
                    <xsl:when  test="(ancestor-or-self::*/parent::*[not(preceding-sibling::*)]/parent::*[matches(name(), '^(msubsup|msub|msup|munder|munderover|mover|msqrt|mroot)$')])">Yes11a</xsl:when>
                </xsl:choose>
            </xsl:for-each>
        </xsl:variable>
    
        <xsl:choose>
            <xsl:when test="contains($varFrac, 'Yes')">
                <xsl:copy>
                    <xsl:apply-templates select="@*"/>
                    <xsl:attribute name="stretchy">true</xsl:attribute>
                    <xsl:apply-templates select="node()"/>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-17
      • 2016-05-11
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 2011-06-05
      相关资源
      最近更新 更多