使用分组将文本拉到一起然后进行测试

时间:2010-02-03 15:38:12

标签: xslt grouping xslt-2.0 xsl-grouping

因此,在这种笨重的挤压排版产品中,我有时会看到已拆分的链接和电子邮件地址。例如:

<p>Here is some random text with an email address 
<Link>example</Link><Link>@example.com</Link> and here 
is more random text with a url 
<Link>http://www.</Link><Link>example.com</Link> near the end of the sentence.</p>

期望的输出:

<p>Here is some random text with an email address 
<email>example@example.com</email> and here is more random text 
with a url <ext-link ext-link-type="uri" xlink:href="http://www.example.com/">
http://www.example.com/</ext-link> near the end of the sentence.</p>

元素之间的空白似乎不会发生,这是一种祝福。

我可以告诉我需要在p模板中使用xsl:for-each-group,但是我无法完全看到如何通过contains()函数将组合文本放入组中以区分电子邮件来自网址。帮助

2 个答案:

答案 0 :(得分:0)

以下是基于身份模板的XSLT 1.0解决方案,对<Link>元素进行了特殊处理。

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

<xsl:template match="Link">
  <xsl:if test="not(preceding-sibling::node()[1][self::Link])">
    <xsl:variable name="link">
      <xsl:copy-of select="
        text()
        | 
        following-sibling::Link[
          preceding-sibling::node()[1][self::Link]
          and
          generate-id(current())
          =
          generate-id(
            preceding-sibling::Link[
              not(preceding-sibling::node()[1][self::Link])
            ][1]
          )
        ]/text()
      " />
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="contains($link, '://')">
        <ext-link ext-link-type="uri" xlink:href="{$link}" />
      </xsl:when>
      <xsl:when test="contains($link, '@')">
        <email>
          <xsl:value-of select="$link" />
        </email>
      </xsl:when>
      <xsl:otherwise>
        <link type="unknown">
          <xsl:value-of select="$link" />
        </link>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:if>
</xsl:template>

我知道使用的XPath表达式是一些毛茸茸的怪物,但在XPath 1.0中选择相邻的兄弟姐妹并不容易(如果有人知道如何在XPath 1.0中做到这一点,请继续告诉我)。

not(preceding-sibling::node()[1][self::Link])

表示“前一个节点不能是<Link>”,例如:“<Link>元素”是“连续第一个”。

following-sibling::Link[
  preceding-sibling::node()[1][self::Link]
  and
  generate-id(current())
  =
  generate-id(
    preceding-sibling::Link[
      not(preceding-sibling::node()[1][self::Link])
    ][1]
  )
]

装置

  • 来自所有后续兄弟<Link>,选择那些
    • 立即关注<Link>(例如,他们不是“连续第一次”),
    • current()节点的ID(始终为“{1}}”的“第一行”必须等于:
    • 最接近的<Link>,它本身就是“连续第一”

如果这是有道理的。

应用于您的输入,我得到:

<Link>

答案 1 :(得分:0)

如果您使用group-adjacent,那么您可以简单地将当前组()串联连接,如

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xsd"
  version="2.0">

  <xsl:template match="p">
    <xsl:copy>
      <xsl:for-each-group select="node()" group-adjacent="boolean(self::Link)">
        <xsl:choose>
          <xsl:when test="current-grouping-key()">
            <xsl:variable name="link-text" as="xsd:string" select="string-join(current-group(), '')"/>
            <xsl:choose>
              <xsl:when test="matches($link-text, '^https?://')">
                <ext-link ext-link-type="uri" xlink:href="{$link-text}">
                  <xsl:value-of select="$link-text"/>
                </ext-link>
              </xsl:when>
              <xsl:otherwise>
                <email><xsl:value-of select="$link-text"/></email>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="current-group()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>