You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单个XSLT文件中实现CDATA内容提取与二次转换?

单个XSLT实现CDATA内容提取与目标XML生成

核心需求:编写单个XSLT文件,先提取源XML中CDATA区段内的XML内容,再基于提取后的内容转换为指定格式的目标XML。

源XML文件

<Docs>
  <Doc>
   <Content>
    <![CDATA[
      <Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <Header DocNumber="1" Description="Desc1"></Header>
        <Poss>
          <Pos Id="1" Name="Pos1"></Pos>
          <Pos Id="2" Name="Pos2"></Pos>
        </Poss>
      </Doc>
   ]]>
  </Content>
 </Doc>
 <Doc>
  <Content>
    <![CDATA[
     <Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Header DocNumber="2" Description="Desc2"></Header>
      <Poss>
        <Pos Id="3" Name="Pos3"></Pos>
        <Pos Id="4" Name="Pos4"></Pos>
      </Poss> 
    </Doc>
  ]]>
 </Content>
</Doc>

现有XSLT(仅提取CDATA)

<?xml version="1.0" encoding="Windows-1250"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <xsl:element name="Docs">
       <xsl:for-each select="Docs/Doc">
        <xsl:value-of select="Content/text()" disable-output-escaping="yes"/>
       </xsl:for-each>
     </xsl:element>
    </xsl:template>
  </xsl:stylesheet>

中间输出

<Docs>
    
      <Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <Header DocNumber="1" Description="Desc1"></Header>
        <Poss>
          <Pos Id="1" Name="Pos1"></Pos>
          <Pos Id="2" Name="Pos2"></Pos>
        </Poss>
      </Doc>       
       
     <Doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Header DocNumber="2" Description="Desc2"></Header>
      <Poss>
        <Pos Id="3" Name="Pos3"></Pos>
        <Pos Id="4" Name="Pos4"></Pos>
      </Poss> 
    </Doc>
  
 </Docs>

目标XML格式

<DOCS>
      <DOC NUMBER="1" DESC="Desc1">
      <POSS>  
        <POS>Pos1</POS>
        <POS>Pos2</POS>
      </POSS>
      </DOC>
      <DOC NUMBER="2" DESC="Desc2">
      <POSS>  
        <POS>Pos3</POS>
        <POS>Pos4</POS>
      </POSS>
      </DOC>
    </DOCS>

解决方案:单个XSLT实现完整转换

由于XSLT 1.0本身无法直接解析CDATA中的XML字符串为节点集,需要借助EXSLT扩展函数(大部分主流XSLT处理器如libxslt、Saxon均支持)来实现。以下是完整的XSLT代码:

<?xml version="1.0" encoding="Windows-1250"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl">

  <!-- 主模板:遍历外层Docs/Doc -->
  <xsl:template match="/">
    <DOCS>
      <xsl:for-each select="Docs/Doc">
        <!-- 将CDATA内容转为临时XML节点 -->
        <xsl:variable name="cdata-xml">
          <xsl:value-of select="Content/text()" disable-output-escaping="yes"/>
        </xsl:variable>
        <!-- 将临时XML转为节点集,以便后续处理 -->
        <xsl:variable name="doc-node" select="exsl:node-set($cdata-xml)/Doc"/>
        
        <!-- 生成目标DOC节点 -->
        <DOC NUMBER="{$doc-node/Header/@DocNumber}" DESC="{$doc-node/Header/@Description}">
          <POSS>
            <!-- 遍历Pos节点,提取Name属性值 -->
            <xsl:for-each select="$doc-node/Poss/Pos">
              <POS><xsl:value-of select="@Name"/></POS>
            </xsl:for-each>
          </POSS>
        </DOC>
      </xsl:for-each>
    </DOCS>
  </xsl:template>

</xsl:stylesheet>

代码解释

  1. 引入EXSLT扩展:通过xmlns:exsl="http://exslt.org/common"声明扩展命名空间,并启用extension-element-prefixes="exsl"让处理器识别扩展函数。
  2. 临时XML节点生成:使用<xsl:variable>将CDATA内容以未转义的形式存入变量,此时变量内容是XML字符串。
  3. 节点集转换:通过exsl:node-set()将XML字符串转换为可遍历的节点集,这样就能像处理普通XML节点一样访问CDATA内的Doc、Header、Pos等元素。
  4. 目标XML生成:基于转换后的节点集,直接提取属性值并生成符合要求的<DOCS>、<DOC>、<POSS>、<POS>结构。

注意事项

  • 确保使用的XSLT处理器支持EXSLT扩展(如libxslt、Saxon 6.x等);若使用XSLT 2.0及以上版本,可直接使用xsl:parse函数解析XML字符串,无需依赖EXSLT。
  • 若CDATA内的XML存在命名空间(如示例中的xsi),无需额外处理,exsl:node-set()会自动保留命名空间,但由于目标XML不需要该命名空间,直接提取属性即可。

内容的提问来源于stack exchange,提问作者jeffers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:25:32