如何使用XSLT删除SOAP信封和命名空间

时间:2014-10-15 00:48:38

标签: xml xslt soap

我有一条消息

<soapenv:Envelope  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns="http://xmlns.oracle.com/policyautomation/hub/12.0/metadata/types">
    <soapenv:Header/>
    <soapenv:Body>          
    <load-request root="Vehicles" region="en-US" language="en-US" timezone="Etc/GMT">
        <tables>
            <table name="Vehicles">
                <link name="Cars" target="Car" />
            </table>
        </tables>
    </load-request>
    </soapenv:Body>

我需要对它进行两次转换:

  • 删除SOAP信封
  • 转换正文内容(加载请求标记)

我知道如何变换load-request,并尝试this solution删除SOAP,但无法将两者合并并删除信封并转换正文(加载请求 )单个xslt。 结果XML应该是:

<load-request>
  <root>Vehicles</root>
  <region>en-US</region>
  <language>en-US</language>
  <timezone>Etc/GMT</timezone>
  <request-context>
    <parameter>
        <name>MyParam1</name>
        <value>MyValue</value>
    </parameter>
  </request-context>
  <tables>
    <table>
        <name>Vehicles</name>
        <link>
        <name>Cars</name>
        <target>Car</target>
        </link>
    </table>
  </tables>
 </load-request>

我使用的XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
<xsl:output method="xml" indent="yes"/> 
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template> 
<xsl:template match="soapenv:*">
    <xsl:apply-templates select="@* | node()" />        
</xsl:template>
<xsl:template match="load-request">
    <xsl:element name="load-request">
        <xsl:element name="root">
            <xsl:value-of select="@root"/>
        </xsl:element>
        <xsl:element name="region">
            <xsl:value-of select="@region"/>
        </xsl:element> 
        <xsl:element name="language">
            <xsl:value-of select="@language"/>
        </xsl:element> 
        <xsl:element name="timezone">
            <xsl:value-of select="@timezone"/>
        </xsl:element> 
        <xsl:apply-templates select="request-context"/> 
        <xsl:apply-templates select="tables"/> 
    </xsl:element>        
</xsl:template>
<xsl:template match="request-context">
    <xsl:element name="request-context">
        <xsl:for-each select="parameter">
            <xsl:element name="parameter">
                <xsl:element name="name">
                    <xsl:value-of select="@name"/>
                </xsl:element>
                <xsl:element name="value">
                    <xsl:value-of select="@value"/>
                </xsl:element>
            </xsl:element>
        </xsl:for-each>
    </xsl:element>        
</xsl:template> 
<xsl:template match="tables">
    <xsl:element name="tables">
        <xsl:for-each select="table">
            <xsl:element name="table">
                <xsl:element name="name">
                    <xsl:value-of select="@name"/>
                </xsl:element> 
                <xsl:apply-templates select="link"/> 
                <xsl:for-each select="field">
                    <xsl:element name="field">
                        <xsl:element name="name">
                            <xsl:value-of select="@name"/>
                        </xsl:element>                   
                    </xsl:element>
                </xsl:for-each>                     
            </xsl:element>
        </xsl:for-each>
    </xsl:element>        
</xsl:template> 
<xsl:template match="link">
    <xsl:element name="link"> 
        <xsl:element name="name">
            <xsl:value-of select="@name"/>
        </xsl:element>
        <xsl:element name="target">
            <xsl:value-of select="@target"/>
        </xsl:element>
    </xsl:element>    
</xsl:template>
<xsl:template match="field">
    <xsl:for-each select="field">
        <xsl:element name="field">
            <xsl:element name="name">
                <xsl:value-of select="@name"/>
            </xsl:element>                   
        </xsl:element>
    </xsl:for-each>        
 </xsl:template> 
</xsl:stylesheet>

更新: 答案适用于输入。你能否请进一步调整: 在我的一些场景中,将属性转换为元素是不够的。

下面的消息
<soapenv:Envelope  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                   xmlns="http://xmlns.oracle.com/policyautomation/hub/12.0/metadata/types">
<soapenv:Header/>
<soapenv:Body>  
    <load-request root="Complains">
        <field name="Explanation">
            <text-val name="Text">The client needs a new toothbrush</text-val>
        </field>
    </load-request>
</soapenv:Body>

需要成为

<load-request>
   <root>Complains</root>
   <field>
     <name>Explanation</name>
     <text-val>
       <name>Text</name>
       <value>The client needs a new toothbrush</value>
     </text-val>
   </field>
</load-request>

1 个答案:

答案 0 :(得分:4)

从更简单的事情开始怎么样:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
exclude-result-prefixes="soapenv">

<xsl:strip-space elements="*"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- remove all elements in the soapenv namespace -->
<xsl:template match="soapenv:*">
    <xsl:apply-templates select="node()"/>
</xsl:template>

<!-- for the remaining elements (i.e. elements in the default namespace) ... -->
<xsl:template match="*">
    <!-- ... create a new element with similar name in no-namespace -->
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>

<!-- convert attributes to elements -->
<xsl:template match="@*">
    <xsl:element name="{local-name()}">
        <xsl:value-of select="." />
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

应用于您的示例输入,已针对格式良好(!)进行修复:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://xmlns.oracle.com/policyautomation/hub/12.0/metadata/types">
  <soapenv:Header/>
  <soapenv:Body>
    <load-request root="Vehicles" region="en-US" language="en-US" timezone="Etc/GMT">
      <tables>
        <table name="Vehicles">
          <link name="Cars" target="Car"/>
        </table>
      </tables>
    </load-request>
  </soapenv:Body>
</soapenv:Envelope>

生成以下结果

<?xml version="1.0" encoding="UTF-8"?>
<load-request>
   <root>Vehicles</root>
   <region>en-US</region>
   <language>en-US</language>
   <timezone>Etc/GMT</timezone>
   <tables>
      <table>
         <name>Vehicles</name>
         <link>
            <name>Cars</name>
            <target>Car</target>
         </link>
      </table>
   </tables>
</load-request>

编辑:

响应您的修改:

如果具有文本值的任何元素都可以转换,以便文本值变为名为value的子元素,则只需在样式表中添加另一个通用模板:

<xsl:template match="text()">
    <value>
        <xsl:value-of select="." />
    </value>
</xsl:template>

如果上述情况不正确,并且您需要显式地处理源XML中的特定元素,那么您需要在样式表中声明源的默认命名空间,为其分配前缀并在寻址元素时使用该前缀。在这种情况下,stylesheet元素将如下所示:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tps="http://xmlns.oracle.com/policyautomation/hub/12.0/metadata/types"
exclude-result-prefixes="soapenv tps">

,您的模板将采用以下形式:

<xsl:template match="tps:text-val">
    <text-val>
        <!-- more instructions here -->
    </text-val>
</xsl:template>