简体   繁体   English

根据第一个点(。)拆分方程式

[英]Split the equation based on first dot (.)

Please suggest for how to split the equation into two parts based on first dot. 请建议如何根据第一个点将方程式分为两部分。 Earlier I got the suggestion to Split the Equation based on BREAK comment text from michael.hor257k, now it is required to split on period. 早些时候,我得到了根据michael.hor257k的BREAK注释文本拆分等式建议 ,现在需要按期拆分。

XML: XML:

<root>
    <body><sec><title>The sec 1</title><p>Text 1</p></sec></body>
    <inline-formula>
        <math display="inline">
            <mi>A</mi>
            <mn>4.651</mn>
            <mi>The next text</mi>
        </math>
    </inline-formula>
    <inline-formula>
        <math display="inline">
            <mrow>
                <mrow><mi>B</mi></mrow>
                <mrow><mn>4.651</mn></mrow>
            </mrow>
            <mi>The next text</mi>
        </math>
    </inline-formula>
</root>

XSLT: XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="root" select="//inline-formula/*" />

    <xsl:template match="/">
        <xsl:for-each select="//inline-formula">
                <xsl:for-each select="text()">
                    <xsl:if test="contains(., '.')">
                        <xsl:apply-templates select="$root">
                            <xsl:with-param name="i" select="." tunnel="yes"/>
                        </xsl:apply-templates>
                    </xsl:if>
                </xsl:for-each >
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:param name="i" tunnel="yes"/>
            <xsl:if test="descendant-or-self::text()[contains(., '.')]">
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:if>
    </xsl:template>

</xsl:stylesheet>

Required Result: 所需结果:

<root>
    <body><sec><title>The sec 1</title><p>Text 1</p></sec></body>
    <inline-formula>
        <math display="inline">
            <mi>A</mi>
            <mn>4.</mn>
        </math>
    </inline-formula>
    <inline-formula>
        <math display="inline">
            <!--Text node, before dot is removed -->
            <mn>651</mn>
            <mi>The next text</mi>
        </math>
    </inline-formula>

    <inline-formula>
        <math display="inline">
            <mrow>
                <mrow><mi>B</mi></mrow>
                <mrow><mn>4.</mn></mrow>
            </mrow>
        </math>
    </inline-formula>
    <inline-formula>
        <math display="inline">
            <mrow>
                <!--Text node, before dot is removed -->
                <mrow><mn>651</mn></mrow>
            </mrow>
            <mi>The next text</mi>
        </math>
    </inline-formula>
</root>

I'm also wondering why you need such a transformation, but here is a possible solution. 我也想知道为什么您需要这样的转换,但这是一个可能的解决方案。 The rules are not clear to me, eg 这些规则对我来说并不明确,例如

  • Can there be more than 2 mn elements in an inline-formula ? inline-formula可以有超过200 mn元素吗?
  • Is it always the string value of mn that needs to be split into separate elements? 是否总是需要将mn的字符串值拆分为单独的元素?
  • You are saying the split should occur on the first . 您是说拆分应该在第一个发生. in the value of mn , but multiple dots do not make sense in a single mn element in MathML mn的值表示,但在MathML中的单个mn元素中多个点没有意义

But setting aside all this, perhaps it's easier to tackle the problem with two separate transformations. 但是,撇开所有这些,也许可以通过两个单独的转换来解决问题。 The first simply separates the content of mn elements: 第一个简单地将mn元素的内容分开:

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

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="mn[contains(.,'.')]">
        <xsl:for-each select="tokenize(.,'\.')">
            <mn>
                <xsl:value-of select="."/>
                <xsl:if test="position() = 1">
                    <xsl:text>.</xsl:text>
                </xsl:if>
            </mn>
        </xsl:for-each>
    </xsl:template>

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

</xsl:stylesheet>

The intermediate result is 中间结果是

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <body>
      <sec>
         <title>The sec 1</title>
         <p>Text 1</p>
      </sec>
   </body>
   <inline-formula>
      <math display="inline">
         <mi>A</mi>
         <mn>4.</mn>
         <mn>651</mn>
         <mi>The next text</mi>
      </math>
   </inline-formula>
   <inline-formula>
      <math display="inline">
         <mrow>
            <mrow>
               <mi>B</mi>
            </mrow>
            <mrow>
               <mn>4.</mn>
               <mn>651</mn>
            </mrow>
         </mrow>
         <mi>The next text</mi>
      </math>
   </inline-formula>
</root>

Then, apply a second transformation similar to the following. 然后,应用类似于以下内容的第二个转换。 By the way, it seems to be a good opportunity to use the special mode keywords #all and #current . 顺便说一句,使用特殊模式关键字#all#current似乎是一个很好的机会。

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

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="inline-formula[count(//mn) gt 1]">
        <xsl:apply-templates select="." mode="first"/>
        <xsl:apply-templates select="." mode="second"/>
    </xsl:template>

    <xsl:template match="mn[position() = 2] | mi[. = 'The next text']" mode="first"/>
    <xsl:template match="mi[. != 'The next text']" mode="second"/>

    <xsl:template match="mn[position() = 1]" mode="second">
        <xsl:comment>Text node, before dot is removed</xsl:comment>
    </xsl:template>


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

</xsl:stylesheet>

and the final result is 最终结果是

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <body>
      <sec>
         <title>The sec 1</title>
         <p>Text 1</p>
      </sec>
   </body>
   <inline-formula>
      <math display="inline">
         <mi>A</mi>
         <mn>4.</mn>
      </math>
   </inline-formula>
   <inline-formula>
      <math display="inline"><!--Text node, before dot is removed-->
         <mn>651</mn>
         <mi>The next text</mi>
      </math>
   </inline-formula>
   <inline-formula>
      <math display="inline">
         <mrow>
            <mrow>
               <mi>B</mi>
            </mrow>
            <mrow>
               <mn>4.</mn>
            </mrow>
         </mrow>
      </math>
   </inline-formula>
   <inline-formula>
      <math display="inline">
         <mrow>
            <mrow/>
            <mrow><!--Text node, before dot is removed-->
               <mn>651</mn>
            </mrow>
         </mrow>
         <mi>The next text</mi>
      </math>
   </inline-formula>
</root>

The result contains an empty mrow element. 结果包含一个空的mrow元素。 If it matters, you could add another template along the lines of 如果有关系,您可以按照以下方式添加另一个模板:

<xsl:template match="mrow/mrow[not(mn)]" mode="second"/>

to the second transformation, but, again, it is not clear how empty elements should be dealt with. 到第二个转换,但是同样,不清楚如何处理空元素。

Looking at the answer to the previous question, provided by michael.hor257k, there are a couple of key differences to the XSLT you are using in this question. 查看由michael.hor257k提供的上一个问题的答案,您在此问题中使用的XSLT有几个主要区别。 In the previous answer, which splits on comments, it iterates the number of times such comments appear 在前面的答案中(拆分评论),迭代出现这些评论的次数

<xsl:for-each select="0 to count(//comment()[.='Break'])">

So, in the new solution, you need to iterate over the number of times a text node occurs with a dot in: 因此,在新解决方案中,您需要遍历文本节点中出现点的次数:

<xsl:for-each select="0 to count(//text()[contains(., '.')])">

Then, in the "identity" template, the previous answer checks the number of comments below the current node to see if it showed be copied: 然后,在“身份”模板中,上一个答案检查当前节点下方的评论数,以查看是否显示了它被复制:

<xsl:if test="descendant-or-self::text()[count(preceding::comment()[.='Break'])=$i]">

This means, in the new solution, you might start off by writing this: 这意味着,在新的解决方案中,您可以通过编写以下代码开始:

<xsl:if test="descendant-or-self::text()[count(preceding::text()[contains(., '.')])=$i]">

However, this would not be entirely correct, as the node with the dot in would be copied to the first part of the split, but the second part of the split would not contain the node at all. 但是,这并不是完全正确的,因为带有点的节点将被复制到拆分的第一部分,但是拆分的第二部分将根本不包含该节点。

The actually expression needed is this: 实际需要的表达式是这样的:

<xsl:if test="descendant-or-self::text()[(count(preceding::text()[contains(., '.')])=($i - 1) and contains(., '.')) or count(preceding::text()[contains(., '.')])=$i]">

This would copied the node containing the dot to both parts of the split. 这会将包含点的节点复制到拆分的两个部分。 You would then need a whole new template to actually split the text. 然后,您将需要一个全新的模板来实际拆分文本。

Try this XSLT 试试这个XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="root" select="/*" />

<xsl:template match="/*">
    <xsl:copy>
        <xsl:copy-of select="*[not(self::inline-formula)]" />
        <xsl:for-each select="0 to count(//text()[contains(., '.')])">
            <xsl:apply-templates select="$root/inline-formula">
                <xsl:with-param name="i" select="." tunnel="yes"/>
            </xsl:apply-templates>
        </xsl:for-each >
    </xsl:copy>
</xsl:template>

<xsl:template match="@*">
    <xsl:copy />
</xsl:template>

<xsl:template match="node()">
    <xsl:param name="i" tunnel="yes"/>
    <xsl:if test="descendant-or-self::text()[(count(preceding::text()[contains(., '.')])=($i - 1) and contains(., '.')) or count(preceding::text()[contains(., '.')])=$i]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

<xsl:template match="text()[contains(., '.')]">
    <xsl:param name="i" tunnel="yes"/>
    <xsl:choose>
        <xsl:when test="count(preceding::text()[contains(., '.')]) = $i">
            <xsl:value-of select="substring-before(., '.')" /><xsl:text>.</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="substring-after(., '.')" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM