如何使用XSLT转换和修改(!)嵌套标签?

时间:2018-09-28 08:07:03

标签: xslt nested transformation xpath-1.0

以这个XML为例...

<list>
  <header>
    something
  </header>
  <main>
    <p>
      (1) nothing <b>special</b> at all.
    </p>
    <p>
      (1a) and <b>another</b> thing.
    </p>
  </main>
</list>

应转换为...

<list>
  <header>
    something
  </header>
  <aside>
    <para nr="(1)">
      nothing <u>special</u> at all.
    </para>
    <para nr="(1a)">
      and <u>another</u> thing.
    </para>
  </aside>
</list>

This Stackoverflow answer was my starting point...

目前,我还没有解决问题的真正方法。我宁愿不引用以前的失败...

1 个答案:

答案 0 :(得分:1)

我不记得回答提到的问题,但是我给出的答案就是采取的方法。您只需要实施一个数字规则...

  1. main转换为aside
  2. 对于每个p标签,根据第一个子文本元素中括号中的值,将nr属性添加到新创建的para标签中
  3. b元素下的p标记转换为u

第二个有点棘手,但是可以使用此模板来实现,该模板利用一些字符串操作来提取括号中的数字

<xsl:template match="p">
    <para nr="{substring-before(substring-after(text()[1], '('), ')')}">
        <xsl:apply-templates select="@*|node()"/>
    </para>
</xsl:template>

(还要注意使用Attribute Value Templates来创建属性)

您还需要一个关联的模板才能从第一个文本节点中删除数字

<xsl:template match="p/text()[1]">
    <xsl:value-of select="substring-after(., ')')" />
</xsl:template>

尽管将b转换为u要容易得多(这是假设b下的p个元素只需更改)。

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

会有一个类似的模板,可以将main更改为aside

尝试使用此XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />

    <!-- This is the Identity Transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

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

    <xsl:template match="p">
        <para nr="{substring-before(substring-after(text()[1], '('), ')')}">
            <xsl:apply-templates select="@*|node()"/>
        </para>
    </xsl:template>

    <xsl:template match="p/text()[1]">
        <xsl:value-of select="substring-after(., ')')" />
    </xsl:template>

    <xsl:template match="p/b">
        <u>
            <xsl:apply-templates select="@*|node()"/>
        </u>
    </xsl:template>
</xsl:stylesheet>