XSLT - 正则表达式只从text()节点中选择一位数字

时间:2016-01-15 08:33:02

标签: regex xml xslt xslt-2.0

我是这样的xml,

 John: 8 Coke 
 Mary: 1 Pie 
 Mary: 2 Water 
 Jack: 3 Milk

这里我需要将<section> <para>height 4cm, width 5cm, weight 343</para> <para>height 2cm, width 6cm, weight 410</para> <para>height 3cm, width 1cm, weight 590</para> </section> 的单个数字加倍。期望的输出应该是,

para/text()

要做到这一点,我有一个这样的模板,

  <section>
        <para>height 8cm, width 10cm, weight 343</para>
        <para>height 4cm, width 12cm, weight 410</para>
        <para>height 6cm, width 2cm, weight 590</para>
    </section>

这里的问题是,这不会将任何一位数字作为一个数字加一个并加倍,

当前输出,

<xsl:template match="para/text()">
        <xsl:analyze-string select="." regex="\d">

            <xsl:matching-substring>
                <xsl:value-of select="2 * number(.)"/>
            </xsl:matching-substring>

            <xsl:non-matching-substring>
                <xsl:value-of select="."/>
            </xsl:non-matching-substring>

        </xsl:analyze-string>
    </xsl:template>

任何建议如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

有几种方法可以解决这个问题。一种方法是要求单个数字后跟&#34; cm&#34; (如果输入XML中的情况总是如此,我们还不知道。)

XSLT样式表

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:template match="para/text()">
        <xsl:analyze-string select="." regex="\dcm">

            <xsl:matching-substring>
                <xsl:value-of select="2 * number(substring-before(.,'cm'))"/>
            </xsl:matching-substring>

            <xsl:non-matching-substring>
                <xsl:value-of select="."/>
            </xsl:non-matching-substring>

        </xsl:analyze-string>
    </xsl:template>

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

XML输出

<section>
    <para>height 8, width 10, weight 343</para>
    <para>height 4, width 12, weight 410</para>
    <para>height 6, width 2, weight 590</para>
</section>

或者,您可以例如要求单个数字后面跟不是数字的东西:

<xsl:template match="para/text()">
    <xsl:analyze-string select="." regex="\d[^\d]">

        <xsl:matching-substring>
            <xsl:value-of select="2 * number(substring(.,1,1))"/>
        </xsl:matching-substring>

        <xsl:non-matching-substring>
            <xsl:value-of select="."/>
        </xsl:non-matching-substring>

    </xsl:analyze-string>
</xsl:template>

如果这始终适用于您的数据,因为它不包括字符串最后一位数字的情况。

要考虑所有可能的情况,请使用

<xsl:template match="para/text()">
    <xsl:analyze-string select="." regex="(^|[^\d])(\d)([^\d]|$)">

        <xsl:matching-substring>
            <xsl:value-of select="regex-group(1)"/>
            <xsl:value-of select="2 * number(regex-group(2))"/>
            <xsl:value-of select="regex-group(3)"/>
        </xsl:matching-substring>

        <xsl:non-matching-substring>
            <xsl:value-of select="."/>
        </xsl:non-matching-substring>

    </xsl:analyze-string>
</xsl:template>

这与michael.hor257k提出的基本相同(在我做之前!)。

答案 1 :(得分:2)

如果您定义一个&#34;单个数字&#34;作为由非数字字符包围的单个数字,您可以使用:

<xsl:template match="para/text()">
    <xsl:analyze-string select="." regex="(\D)(\d)(\D)">

    <xsl:matching-substring>
        <xsl:value-of select="regex-group(1)"/>
        <xsl:value-of select="2 * number(regex-group(2))"/>
        <xsl:value-of select="regex-group(3)"/>
    </xsl:matching-substring>

    <xsl:non-matching-substring>
        <xsl:value-of select="."/>
    </xsl:non-matching-substring>

    </xsl:analyze-string>
</xsl:template>

请注意,这不会捕获字符串开头或结尾的单位数字。要包含这些,您必须使用:

<xsl:analyze-string select="." regex="(^|\D)(\d)(\D|$)">