XSLT - 需要复制多个名称空间

时间:2011-09-17 08:22:11

标签: xml xslt xpath

我有以下XML。我必须在肥皂信封下加入肥皂体。

<headers>
    <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:def="http://lmn" xmlns:abc="http://xyz"><soapenv:Header><abc:Security>    <abc:UsernameToken>
    <abc:Username>abc</abc:Username>
                        <abc:Password>pwd</abc:Password>
                    </abc:UsernameToken>
            </abc:Security>
        </soapenv:Header> 
    </soapenv:Envelope>
 </headers>

我的输出应该像

     <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:def="http://lmn" xmlns:abc="http://xyz">
         <soapenv:Header>
            <abc:Security>
                    <abc:UsernameToken>
                        <abc:Username>abc</abc:Username>
                        <abc:Password>pwd</abc:Password>
                    </abc:UsernameToken>
            </abc:Security>
        </soapenv:Header> 
        <soapenv:Body><a><b></b><c></c></a></soapenv:Body>
     </soapenv:Envelope>

以下是我的XSL。

 <?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:soap="http://www.w3.org/2003/05/soap-envelope" exclude-result-prefixes="xd soap soapenv">
 <xsl:template match="/">
         <xsl:variable name="envNode"><xsl:copy-of select="name(headers/*)"/></xsl:variable>
         <xsl:choose>
             <xsl:when test="contains($envNode,'soapenv')">
                 <xsl:element name="{name(headers/*)}">                   
                     <xsl:copy-of select="headers/soapenv:Envelope/*"/>
                     <xsl:element name="soapenv:Body">
                         <a><b></b><c></c></a>
                     </xsl:element>
                 </xsl:element>
             </xsl:when>
             <xsl:otherwise>
                <xsl:element name="{name(soapOptions/headers/*)}">                   
            <xsl:copy-of select="soapOptions/headers/soap:Envelope/*"/>
            <xsl:element name="soap:Body">
                 <a><b></b><c></c></a>
            </xsl:element>
             </xsl:element>
            </xsl:otherwise>
         </xsl:choose>
  </xsl:template> 

我得到以下输出。

  <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
    <soapenv:Header xmlns:def="http://lmn" xmlns:abc="http://xyz"">
            <abc:Security>
                    <abc:UsernameToken>
                        <abc:Username>abc</abc:Username>
                        <abc:Password>pwd</abc:Password>
                    </abc:UsernameToken>
            </abc:Security>
        </soapenv:Header>
        <soapenv:Body><a><b/><c/></a></soapenv:Body>
 </soapenv:Envelope>

我想将soapenv:Envelope节点中的所有命名空间复制到同一节点。但它被复制到soapenv:Header。      我尝试了许多选项命名空间选项以及XSL中元素名称中的命名空间。      任何人都可以帮助我。

提前致谢, 纳杰马

2 个答案:

答案 0 :(得分:2)

在元素声明下添加:

 <xsl:copy-of select="headers/*/namespace::*"/>

这将在正确的元素中复制所需的命名空间,从而阻止XSLT处理器在其他地方声明它们。


XSLT验证:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:element name="{name(headers/*)}">
            <xsl:copy-of select="headers/*/namespace::*"/>
            <xsl:copy-of select="headers/soapenv:Envelope/*"/>
            <xsl:element name="soapenv:Body">
                <a><b></b><c></c></a>
            </xsl:element>
        </xsl:element>

    </xsl:template>

</xsl:stylesheet>

产生

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:def="http://lmn" xmlns:abc="http://xyz">
   <soapenv:Header>
      <abc:Security>
         <abc:UsernameToken>
            <abc:Username>abc</abc:Username>
            <abc:Password>pwd</abc:Password>
         </abc:UsernameToken>
      </abc:Security>
   </soapenv:Header>
   <soapenv:Body>
      <a>
         <b/>
         <c/>
      </a>
   </soapenv:Body>
</soapenv:Envelope>

但是,如果您可以更改样式表,我会使用更简单的内容:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="headers">
        <xsl:apply-templates select="node()"/>
    </xsl:template>

    <xsl:template match="soapenv:Header">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
            <soapenv:Body>
                <a><b></b><c></c></a>
            </soapenv:Body>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

使用可能是最短,最简单和最标准化的解决方案

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

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

 <xsl:template match="soapenv:Envelope">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
   <soapenv:Body><a><b/><c/></a></soapenv:Body>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<headers>
    <soapenv:Envelope
      xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"
      xmlns:def="http://lmn" xmlns:abc="http://xyz">
        <soapenv:Header>
            <abc:Security>
                <abc:UsernameToken>
                    <abc:Username>abc</abc:Username>
                    <abc:Password>pwd</abc:Password>
                </abc:UsernameToken>
            </abc:Security>
        </soapenv:Header>
    </soapenv:Envelope>
</headers>

产生了想要的正确结果

<headers>
   <soapenv:Envelope
    xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"
    xmlns:def="http://lmn" xmlns:abc="http://xyz">
      <soapenv:Header>
         <abc:Security>
            <abc:UsernameToken>
               <abc:Username>abc</abc:Username>
               <abc:Password>pwd</abc:Password>
            </abc:UsernameToken>
         </abc:Security>
      </soapenv:Header>
      <soapenv:Body>
         <a>
            <b/>
            <c/>
         </a>
      </soapenv:Body>
   </soapenv:Envelope>
</headers>

<强>解释

  1. identity rule/template按“原样”复制每个节点

  2. 只有一个模板会覆盖身份规则。它与soapenv:Envelope匹配。处理与身份模板的处理非常相似(匹配的元素是“浅层复制的,其所有后代都在其体内复制)”,此外,新的{ {1}}也会输出。