XSLT:在文本分隔符上拆分元素内容,保留元素

时间:2014-06-01 23:19:52

标签: xslt xml-parsing tokenize

我尝试解析元素内容并将其拆分为分隔符,同时将所有元素保留在父级中。我不需要 - 不想要 - 在子元素中找到分隔符。

<data>
  <parse-field>Some text <an-element /> more text; cheap win? ;
    <another-element>with delimiter;!</another-element>; final text</parse-field>
</data>

应该成为

<data>
  <parsed-field>
    <field>Some text <an-element /> more text</field>
    <field>cheap win?</field>
    <field><another-element>with limiter;!</another-element></field>
    <field>final text</field>
  </parsed-field>
</data>

我有一个黑客攻击的解决方案,可以检查所有&#34;解析字段/文本()&#34;然后用<token />替换分隔符,然后用第二遍来挑选<token>周围的部分,但它已被黑了。而且不愉快。我想知道是否有更好的方式。

我正在使用XSLT-2.0,对XSLT-1.0解决方案开放。 SAXON处理器。

2 个答案:

答案 0 :(得分:2)

这不是(还是?)一个完整的答案,只是一个可能的方法的概述。如果你想第一次通过这样的话:

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

<xsl:template match="parse-field/text()">
    <xsl:call-template name="tokenize">
        <xsl:with-param name="text" select="."/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="';'"/>
    <xsl:choose>
        <xsl:when test="contains($text, $delimiter)">
            <field>
                <xsl:value-of select="substring-before($text, $delimiter)"/>
            </field>
            <!-- recursive call -->
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="position()=last()">
            <field><xsl:value-of select="$text"/></field>
        </xsl:when>
        <xsl:when test="$text">
            <text><xsl:value-of select="$text"/></text>
        </xsl:when>
    </xsl:choose>
</xsl:template>

你会得到:

<?xml version="1.0" encoding="UTF-8"?>
<data>
   <parse-field>
      <text>Some text </text>
      <an-element/>
      <field> more text</field>
      <field> cheap win? </field>
      <another-element>with delimiter;!</another-element>
      <field/>
      <field> final text</field>
   </parse-field>
</data>

现在这是一个分组问题,需要对<parse-field>的元素进行分组,每个组都以<field>结尾。

答案 1 :(得分:1)

我迄今为止采用的最佳方式,简单形式:

<xsl:variable name="delimiter" select="';'" />

<xsl:template match="foo">
  <xsl:copy>
    <xsl:apply-templates select="@*" />
    <xsl:call-template name="tokenize" />
  </xsl:copy>
</xsl:template>

<xsl:template name="tokenize">
  <xsl:variable name="rough">
    <xsl:apply-templates mode="tokenize" />
  </xsl:variable>
  <xsl:copy>
    <xsl:group-by select="$rough/*" group-ending-with="delimiter">
      <field><xsl:apply-templates select="current-group()[not(self::delimiter)]" /></field>
    </xsl:group>
  </xsl:copy>
</xsl:template>

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

<xsl:template match="text()" mode="tokenize">
  <xsl:analyze-string select="." regex="([^{$delimiter}]*){$delimiter}">
    <xsl:matching-substring>
      <xsl:value-of select="regex-group(1)" /><delimiter/>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:value-of select="." />
    </xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:template>