如何使用 XSLT 删除 SOAP 信封和名称空间 [英] How to remove SOAP envelope and namespaces with XSLT

查看:20
本文介绍了如何使用 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>

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

and I need to make two transformations to it:

  • 删除 SOAP 信封
  • 转换正文的内容(load-request 标记)

我知道如何变形加载请求,并尝试了此解决方案来删除 SOAP,但无法将两者结合起来并移除信封并使用单个 xslt 转换正文(加载请求).结果 XML 应该是:

I do know how to morph load-request, and tried this solution to remove SOAP, but cannot manage to combine the two and remove the envelope AND transform the body (load-request) with single xslt. The result XML should be:

<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>

更新:答案适用于输入.你能否权衡一下额外的调整:在我的一些场景中,将属性转换为元素是不够的.下面留言

Update: The answer works for the input. Could you please weigh in on additional tweak: In some of my scenarios turning attributes into elements is not enough. The message below

<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>

推荐答案

如何从更简单的事情开始:

How about starting with something much simpler:

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>

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

Applied to your example input, fixed for well-formedness(!):

<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的子元素,您可以简单地向样式表添加另一个通用模板:

If any element with a text value can be transformed so that the text value turns into a child element named value, you could simply add another generic template to the stylesheet:

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

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

If the above is not true, and you need to address a specific element in the source XML explicitly, then you will need to declare the source's default namespace in your stylesheet, assign it a prefix and use that prefix when addressing the element. The stylesheet element, in such case, would look like this:

<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">

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

and your template would be in the form of:

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

这篇关于如何使用 XSLT 删除 SOAP 信封和名称空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆