xml - 建议 xpath 检查相同类型的嵌套元素中的第一个 'text' 节点

标签 xml xpath xslt-2.0

请建议 xpath 来检查元素“mo”是否在“mfrac”的第一个子元素中以“文本节点”开头。当前的 XSLT 代码对于所有“mfrac”都成功运行,其中这些代码不应嵌套在另一个“mfrac”中(数学 1 和 2 成功运行,但数学 3 未成功运行)。如果 'mfrac' 被另一个 'mfrac' 嵌套,则会出现一些错误消息。如果“mo”在“mfrac/child::*”中没有前面的文本节点(“mo”作为第一个文本节点),则所需的输出是“mo”应该获取属性“form=prefix”。请建议如何避免出现错误消息。忽略结果文本中的注释。

XML:

<article>
<body>
    <p>
        <math id="eq1"><mi>i</mi>
            <mfrac>
                <mrow><mo>+</mo></mrow>
                <mrow><mi>t</mi></mrow>
            </mfrac>
        </math>
        <math id="eq2">
            <mfrac>
                <mrow><mi>i</mi><mo>+</mo></mrow>
                <mrow><mi>t</mi></mrow>
            </mfrac>
        </math>

        <math id="eq3"><mi>i</mi><mfrac><mrow><mfrac><mo>+</mo><mi>n</mi></mfrac></mrow><mrow><mi>t</mi></mrow></mfrac></math>
    </p>
</body>
</article>

XSLT:

<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="mo">
    <xsl:choose>
        <xsl:when test="string-length(preceding::text()[1]
                  [normalize-space(.)!='']
                  [generate-id(ancestor-or-self::*[count(preceding-sibling::*)=0]/parent::*[name()='mfrac'])=generate-id(current()/ancestor-or-self::*[count(preceding-sibling::*)=0]/parent::*[name()='mfrac'])]) eq 0">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="form" select="'prefix'"/>
            <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>

所需输出:

<article>
<body>
    <p>
        <mmlmath id="eq1"><mi>i</mi>
            <mfrac>
                <mrow><mo form="prefix">+</mo></mrow><!--Here prefix attribute required because MO found as first text node within MFRAC's first child-->
                <mrow><mi>t</mi></mrow>
            </mfrac>
        </mmlmath>
        <mmlmath id="eq2">
            <mfrac>
                <mrow><mi>i</mi><mo>+</mo></mrow><!--Here attribute not required because 'MO' is not a first text node-->
                <mrow><mi>t</mi></mrow>
            </mfrac>
        </mmlmath>

        <mmlmath id="eq3"><mi>i</mi><mfrac><mrow><mfrac><!--Nested MFRAC--><mo form="prefix">+</mo><!--Attribute required here--><mi>n</mi></mfrac></mrow><mrow><mi>t</mi></mrow></mfrac></mmlmath>
    </p>
</body>
</article>

错误消息:

XPTY0004: A sequence of more than one item is not allowed as the first argument of  generate-id() (<mfrac/>, <mfrac/>)

最佳答案

您应该能够测试当前的 mo 是否是包含 text() 的第一个祖先 mfrac 的第一个后代> 节点。

希望这是有道理的。 :-)

这是一个应该有所帮助的示例...

XML 输入

<article>
    <body>
        <p>
            <math id="eq1">
                <mi>i</mi>
                <mfrac>
                    <mrow>
                        <mo>+</mo>
                    </mrow>
                    <mrow>
                        <mi>t</mi>
                    </mrow>
                </mfrac>
            </math>
            <math id="eq2">
                <mfrac>
                    <mrow>
                        <mi>i</mi>
                        <mo>+</mo>
                    </mrow>
                    <mrow>
                        <mi>t</mi>
                    </mrow>
                </mfrac>
            </math>
            <math id="eq3">
                <mi>i</mi>
                <mfrac>
                    <mrow>
                        <mfrac>
                            <mo>+</mo>
                            <mi>n</mi>
                        </mfrac>
                    </mrow>
                    <mrow>
                        <mi>t</mi>
                    </mrow>
                </mfrac>
            </math>
        </p>
    </body>
</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="mo[. is (ancestor::mfrac[1]//*[text()])[1]]">
        <xsl:copy>
            <xsl:attribute name="form" select="'prefix'"/>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

XML 输出

<article>
   <body>
      <p>
         <math id="eq1">
            <mi>i</mi>
            <mfrac>
               <mrow>
                  <mo form="prefix">+</mo>
               </mrow>
               <mrow>
                  <mi>t</mi>
               </mrow>
            </mfrac>
         </math>
         <math id="eq2">
            <mfrac>
               <mrow>
                  <mi>i</mi>
                  <mo>+</mo>
               </mrow>
               <mrow>
                  <mi>t</mi>
               </mrow>
            </mfrac>
         </math>
         <math id="eq3">
            <mi>i</mi>
            <mfrac>
               <mrow>
                  <mfrac>
                     <mo form="prefix">+</mo>
                     <mi>n</mi>
                  </mfrac>
               </mrow>
               <mrow>
                  <mi>t</mi>
               </mrow>
            </mfrac>
         </math>
      </p>
   </body>
</article>

关于xml - 建议 xpath 检查相同类型的嵌套元素中的第一个 'text' 节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32252018/

相关文章:

android - 任务应用程序执行失败 :generateDebugRFile Error: ':' is not a valid resource name character

Python - 使用 minidom 解析时理解 XML 结构

xml - 是否有类似于 XMLSpy 的具有 GridView 的 XML 编辑器?

bash - 将 grep/xargs 的结果放在单独的行上

xml - 使用 XSLT 将 XML 标签转换为任意位置的属性

xml - 将 XML 子项导入为 Excel 中的列

Selenium 元素选择器 - 我认为 xPath 最慢?

VB.Net XmlDocument.SelectNodes(xPath) : unable to query WSDL

java - XSL - 匹配节点的文本并附加另一个节点作为同级节点

xml - 使用 XSLT 将数字四舍五入到最低百位