使用XSLT将多个命名空间添加到SOAP XML消息

时间:2013-02-05 02:38:36

标签: xml xslt soap namespaces

我有一个SOAP请求,我试图使用XSLT进行转换。我想为命令中的每个元素添加命名空间限定符。我需要用户使用两个不同的命名空间。这是我正在尝试转换的XML:

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" >
   <soapenv:Header/>
   <soapenv:Body>
      <PingRq>
         <RqUID>1</RqUID>
         <RequestContext>
              <ClientUserID>1</ClientUserID>
              <ClientName>Big Company</ClientName>
              <ClientApplication>
                  <AppName>TestApp</AppName>
                  <AppVersion>1</AppVersion>
              </ClientApplication>
              <ClientLangPref>En-US</ClientLangPref>
              <ClientDt>Mar-29-2013</ClientDt>
         </RequestContext>
      </PingRq>
      </soapenv:Body>
    </soapenv:Envelope

以下是我想将其转换为:

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" >
      <soapenv:Header/>
      <soapenv:Body>
       <PingRq namespace="http://www.ns1.com">
         <RqUID namespace="http://www.ns2.com">1</RqUID>
         <RequestContext namespace="http://www.ns2.com">
              <ClientUserID namespace="http://www.ns2.com">1</ClientUserID>
              <ClientName namespace="http://www.ns2.com">Big Company</ClientName>
              <ClientApplication namespace="http://www.ns2.com">
                  <AppName namespace="http://www.ns2.com">TestApp</AppName>
                  <AppVersion namespace="http://www.ns2.com">1</AppVersion>
              </ClientApplication>
              <ClientLangPref namespace="http://www.ns2.com">En-US</ClientLangPref>
              <ClientDt namespace="http://www.ns2.com">Mar-29-2013</ClientDt>
         </RequestContext>
         </PingRq>
       </soapenv:Body>
    </soapenv:Envelope>

这是我的样式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" 
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

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

     <xsl:template match="PingRq">
    <xsl:element name="{local-name()}" namespace="http://www.ns1.com">
        <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
     </xsl:template>
     <xsl:template match="PingRq/*">
    <xsl:element name="{local-name()}" namespace="http://www.ns2.com">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
     </xsl:template>        
    </xsl:stylesheet>

这是我得到的结果。

<?xml version="1.0" encoding="UTF-8"?>
     <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
       <soapenv:Header/>
       <soapenv:Body>
        <PingRq xmlns="http://www.ns1.com">
         <RqUID xmlns="http://www.ns2.com">1</RqUID>
         <RequestContext xmlns="http://www.ns2.com">
              <ClientUserID xmlns="">1</ClientUserID>
              <ClientName xmlns="">Big Company</ClientName>
              <ClientApplication xmlns="">
                  <AppName>TestApp</AppName>
                  <AppVersion>1</AppVersion>
              </ClientApplication>
              <ClientLangPref xmlns="">En-US</ClientLangPref>
              <ClientDt xmlns="">Mar-29-2013</ClientDt>
         </RequestContext>
        </PingRq>
       </soapenv:Body>
      </soapenv:Envelope>

我无法弄清楚为什么我在后代中获取空命名空间属性。任何人有任何想法???

1 个答案:

答案 0 :(得分:1)

PingRq/* xpath仅匹配PingRq元素的直接子元素。要将其所有后代元素放在某个命名空间中,您可以这样做:

<xsl:template match="PingRq//*">
  <xsl:element name="{local-name()}" namespace="http://www.ns2.com">
    <xsl:apply-templates select="@*|node()"/>
   </xsl:element>
</xsl:template>

请注意,结果不会显示所有后代的名称空间声明:

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
  <soapenv:Header />
  <soapenv:Body>
    <PingRq xmlns="http://www.ns1.com">
      <RqUID xmlns="http://www.ns2.com">1</RqUID>
      <RequestContext xmlns="http://www.ns2.com">
        <ClientUserID>1</ClientUserID>
        <ClientName>Big Company</ClientName>
        <ClientApplication>
          <AppName>TestApp</AppName>
          <AppVersion>1</AppVersion>
        </ClientApplication>
        <ClientLangPref>En-US</ClientLangPref>
        <ClientDt>Mar-29-2013</ClientDt>
      </RequestContext>
    </PingRq>
  </soapenv:Body>
</soapenv:Envelope>

但这是可以预料到的,因为RequestContext下的元素是从父节点继承它们的命名空间。