基于XSLT的替换在不同的嵌套级别上

时间:2016-02-13 18:30:44

标签: xml xslt

以下是在不同嵌套级别上包含关键元素srds的XML文档:

<doc>
  <p>
    <sr>some text 1</sr>
    <ds>some text 2</ds>
  </p>
  <p>
    <span>
      <sr>some text 3</sr>
      <ds>some text 4</ds>
    </span>
    <span>
      <sr><b>some</b> text 5</sr>
      <ds>some text <sup>6</sup></ds>
    </span>
  </p>
  <td colspan="2">
    <sr><b>some</b> text 7</sr>
    <ds>some text <b>8</b></ds>
  </td>
</doc>

任务是按原样输出HTML,但遇到<sr><ds>元素时,请对父元素执行一些修改:

  1. sr的内容放入父元素的title属性中,删除所有嵌套标记;只保留纯文本
  2. ds元素的内容原样放入父元素的主体,并使用所有嵌套标记
  3. 例如,上述文档应如下所示:

    <body>
      <p title="some text 1">some text 2</p>
      <p>
        <span title="some text 3">some text 4</span>
        <span title="some text 5">some text <sup>6</sup></span>
      </p>
      <td colspan="2" title="some text 7">some text <b>8</b></td>
    </body>
    

    这可以用XSLT吗?

    目前我只知道如何在固定的嵌套级别(如<xsl:for-each select="/level1/level2">)上处理XML元素,或者如何选择不同级别的元素但只选择它们,而我的任务是按原样输出其余的元素。

    你能给出一个线索吗?

    有时我认为将文档完全读入字符串并在没有XSLT的情况下进行一系列普通字符串替换会更简单。

2 个答案:

答案 0 :(得分:2)

以这种方式尝试:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="/doc">
    <body>
        <xsl:apply-templates/>
    </body>
</xsl:template>

<xsl:template match="sr">
    <xsl:attribute name="title">
        <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>

<xsl:template match="ds">
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>

请注意,这假设sr始终位于ds或任何其他同级元素之前。

答案 1 :(得分:0)

以下解决方案无论srds元素的顺序如何都有效:

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

  <xsl:template match="*[sr and ds]" priority="8">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="title"><xsl:value-of select="sr"/></xsl:attribute>
      <xsl:apply-templates/> 
    </xsl:copy>
  </xsl:template>
  <xsl:template match="/*" priority="9">
    <body>
      <xsl:apply-templates/>
    </body>
  </xsl:template>
  <xsl:template match="sr" priority="10"/>
</xsl:stylesheet>

应用于提供的XML文档的此变体(请注意srds的任意顺序):

<doc>
  <p>
    <ds>some text 2</ds>
    <sr>some text 1</sr>
  </p>
  <p>
    <span>
      <sr>some text 3</sr>
      <ds>some text 4</ds>
    </span>
    <span>
      <sr><b>some</b> text 5</sr>
      <ds>some text <sup>6</sup></ds>
    </span>
  </p>
  <td colspan="2">
    <ds>some text <b>8</b></ds>
    <sr><b>some</b> text 7</sr>
  </td>
</doc>

产生了想要的正确结果

<body>
   <p title="some text 1">some text 2</p>
   <p>
      <span title="some text 3">some text 4</span>
      <span title="some text 5">some text <sup>6</sup>
      </span>
   </p>
   <td colspan="2" title="some text 7">some text <b>8</b>
   </td>
</body>