Xpath / XSLT返回部分字符串

时间:2014-01-20 13:01:54

标签: xml xslt xpath

我正在使用XSLT 2.0和xpath 2.0。我在编写一个<xsl:value-of select="">时会遇到段落中的前导段号,同时仍保留段落中的所有元素。例如:

<p>(1) This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>

对此:

<p>
  <b>(1)<b> This paragraph may have <i>italics</i>, <b>bold</b> and other elements.
</p>

以下是我的详细代码,部分符合我的需求:

    <xsl:template match="p[substring(.,1,1) = '('][string-length(substring-before(.,')')) &lt; 5]">
    <xsl:variable name="paragraphnumber">
        <xsl:value-of select="substring-after(substring-before(.,')'),'(')"/>
    </xsl:variable>
    <xsl:variable name="parenthesednumber" select="concat('(',$paragraphnumber,')')"/>
    <p>
        <b>
            <xsl:value-of select="$parenthesednumber"/>
        </b>
        <xsl:value-of select="translate(.,$parenthesednumber,'')"/>
    </p>
</xsl:template>    

模板匹配确保我们只匹配以(开头的段落,而结束)之后只有5个字符,允许3个字符的段落编号或文字。

我遇到的问题是我可以获取文本的最后一个value-of,而不是该段中的其他元素。

4 个答案:

答案 0 :(得分:1)

我会说,使用单独的模板是一种更好的方法。通过这样做,您可以确保“权力分配”,并更容易查明错误的代码。

下面的样式表通过matches()在XSLT中使用正则表达式功能:

<xsl:template match="p[matches(./text()[1],'^\([0-9]+\)')]">

上面的模板匹配p元素,如果它们的第一个文本节点以“(”,后跟一个或多个数字和“)”开头。如果是这种情况,则检索括号中的数字 - 利用substring-before()总是以搜索字符串的第一个出现为目标的事实(此处:空格)。

<强>样式表

编辑:@Erwin Bolwidt建议。

<?xml version="1.0" encoding="utf-8"?>

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

<xsl:output method="xml" indent="no"/>

<xsl:template match="p[matches(./text()[1],'^\([0-9]+\)')]">
  <xsl:copy>
     <b>
        <xsl:value-of select="substring-before(.,' ')"/>
     </b>
     <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="p|i|b|text()">
  <xsl:copy>
     <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="text()[matches(.,'^\([0-9]+\)') and parent::p and position() = 1]">
  <xsl:value-of select="substring-after(.,' ')"/>
</xsl:template>

</xsl:stylesheet>

<强>输出

<?xml version="1.0" encoding="UTF-8"?><p><b>(1)</b>This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>

仅举例说明,如果您的输入如下:

<p>(2) Text1 <b/>(1) Text2</p>

括号中的第一个数字应位于b元素中,第二个数字应保持不变。这是你得到的输出:

<?xml version="1.0" encoding="UTF-8"?><p><b>(2)</b>Text1 <b/>(1) Text2</p>

为什么您的方法不起作用

我假设有这一行:

<xsl:value-of select="translate(.,$parenthesednumber,'')"/>

您打算输出<p>的剩余内容。但是,您只输出p元素的文本内容,而不输出其子元素。您需要明确说明它们也应该被处理 - 例如使用apply-templates

答案 1 :(得分:1)

我会用这样的东西:

<xsl:template match="p/text()[1]">
  <xsl:analyze-string select="." regex="\(\d+\)">
   <xsl:matching-substring>
     <b><xsl:value-of select="."/></b>

将“p”元素转换为包含第一个文本节点中额外“b”元素的元素。

答案 2 :(得分:0)

我认为最好在具有(n)数字的段落中的第一个文本节点上进行特定匹配,它使您可以自由地使用身份转换来复制/转换其他节点(文本/元素)在该段中。

警告:我手边只有一个XPath / XSLT 1.0处理器,但我相信这里没有任何内容在1.0和2.0之间有所不同。

样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="p/text()[1][substring(.,1,1) = '('][string-length(substring-before(.,')')) &lt; 5]">
        <xsl:variable name="paragraphnumber">
            <xsl:value-of select="substring-after(substring-before(.,')'),'(')" />
        </xsl:variable>
        <xsl:variable name="parenthesednumber" select="concat('(',$paragraphnumber,')')" />
        <b>
            <xsl:value-of select="$parenthesednumber" />
        </b>
        <xsl:value-of select="translate(.,$parenthesednumber,'')" />
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

输出:

<p><b>(1)</b> This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>

答案 3 :(得分:0)

正如Michael Kay建议的那样,你可以做这样的事情

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

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

    <xsl:template match="p/text()[1]">
        <xsl:analyze-string select="." regex="\(.{{1,3}}\)">
            <xsl:matching-substring>
                <b><xsl:value-of select="."/></b>
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <xsl:value-of select="."/>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>
</xsl:stylesheet>

它搜索以“(”开头,以“)”开头的第一个文本节点,里面有1-3个字符。应用于XML输入时:

<root>
    <p>(abc4) This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
    <p>(123) This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
    <p>(1ab) This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
    <p>(a1) This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
</root>

它产生:

<root>
    <p>(abc4) This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
    <p><b>(123)</b> This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
    <p><b>(1ab)</b> This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
    <p><b>(a1)</b> This paragraph may have <i>italics</i>, <b>bold</b> and other elements.</p>
</root>