动态XSLT转换

时间:2015-10-21 20:27:08

标签: xslt

我在下面有一个传入的简单xml请求,需要转换为具有正确名称空间的SOAP消息。在传入的XML请求中,名称空间不会出现,因此在形成SOAP消息时我们需要处理名称空间也。是否有任何XSLT代码片段可以帮助我实现这一目标。 注意 - 我们需要动态地进行这种XSLT转换,就像传入请求可以是任何元素一样,例如" GetImageRequest"所以基于这个元素需要构造名称空间。 (可能我们可以将所有名称空间保留在一个xml文件中,并且需要构造SOAP消息)

传入XML请求:

<request>
<payload>
<GetImageRequest>
   <participantId>1191152220010</participantId>
   <participantCode>131029</participantCode>
   <groupCode>027198</groupCode>
   <userType>EE</userType>
   <clientName>Test</clientName>
   <shoeboxID>123444</shoeboxID>
   <imageID>45235</imageID>
</GetImageRequest>
</payload>
</request>

================== 需要使用适当的命名空间构造下面的SOAP消息。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>

   </soapenv:Header>
   <soapenv:Body>
      <get:GetShoeboxItemRequest xmlns:get="urn:webservice/server/mobile/shoebox/types/v1/GetShoeboxItem">
         <get:participantId>1060687620010</get:participantId>
         <get:participantCode>1060687620010</get:participantCode>
         <get:groupCode>027198</get:groupCode>
         <get:userType>EE</get:userType>
         <get:clientName>Test</get:clientName>
         <get:shoeboxID>123444</get:shoeboxID>
      </get:GetShoeboxItemRequest>
   </soapenv:Body>
</soapenv:Envelope>

需要快速帮助。 XSLT代码段会很有帮助。

2 个答案:

答案 0 :(得分:4)

此转化

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

 <xsl:param name="pRequestedItemName" select="'Shoebox'"/>

 <xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
 <xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/>

 <xsl:variable name="vLcItemName" select=
                "translate($pRequestedItemName, $vUpper, $vLower)"/>

 <xsl:variable name="vDynNamespace" select=
   "concat('urn:webservice/server/mobile/', $vLcItemName, '/types/v1/Get', 'Item')"/>

  <xsl:template match="/">
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
            <soapenv:Header>
            </soapenv:Header>
            <soapenv:Body>
              <xsl:element name="get:Get{$pRequestedItemName}ItemRequest" 
                   namespace="{$vDynNamespace}">
                <xsl:apply-templates select="/*/*/GetImageRequest/node()"/>
              </xsl:element>
            </soapenv:Body>
        </soapenv:Envelope>
  </xsl:template>

  <xsl:template match="*">
    <xsl:element name="get:{name()}" namespace="{$vDynNamespace}">
      <xsl:copy-of select="namespace::*|@*"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

应用于提供的源XML文档

<request>
    <payload>
        <GetImageRequest>
            <participantId>1191152220010</participantId>
            <participantCode>131029</participantCode>
            <groupCode>027198</groupCode>
            <userType>EE</userType>
            <clientName>Test</clientName>
            <shoeboxID>123444</shoeboxID>
            <imageID>45235</imageID>
        </GetImageRequest>
    </payload>
</request>

生成想要的正确结果

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <get:GetShoeboxItemRequest
         xmlns:get="urn:webservice/server/mobile/shoebox/types/v1/GetItem">
         <get:participantId>1191152220010</get:participantId>
         <get:participantCode>131029</get:participantCode>
         <get:groupCode>027198</get:groupCode>
         <get:userType>EE</get:userType>
         <get:clientName>Test</get:clientName>
         <get:shoeboxID>123444</get:shoeboxID>
         <get:imageID>45235</get:imageID>
      </get:GetShoeboxItemRequest>
   </soapenv:Body>
</soapenv:Envelope>

<强>解释

  1. 使用 <xsl:element> 指令的全部功能。
  2. 使用 AVT Attribute Value Templates
  3. 动态命名空间的唯一可变部分应由转换的调用者提供为 a global parameter
  4. 如果您需要构建一个完全动态的命名空间(例如转换的调用者传入一个全局参数),请参阅 this answer

    <强>更新

    OP在评论中澄清说,他可以在一个单独的XML文档或全局参数中收集所有特定于请求的命名空间。

    以下是此澄清问题的解决方案

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:param name="pRequestData">
       <r name="GetImageRequest" 
        ns="urn:webservice/server/mobile/shoebox/types/v1/GetShoeboxItem"/>
       <r name="SaveShoeBoxitemRequest" 
        ns="urn:webservice/server/mobile/shoebox/types/v1/SaveShoeboxItem"/>
       <r name="SaveClaimWithReceiptRequest" 
        ns="urn:webservice/server/mobile/shoebox/types/v1/SaveClaimAndReceipt"/>
       <r name="GetThumbNailImageRequest" 
        ns="urn:webservice/server/mobile/shoebox/types/v1/GetThumbnail"/>
       <r name="AttachReceiptwithExistingClaimRequest" 
        ns="urn:webservice/server/mobile/shoebox/types/v1/AttachClaimAndReceipt"/>
     </xsl:param>
    
     <xsl:variable name="vParams" select="document('')/*/xsl:param[@name='pRequestData']"/>
    
      <xsl:template match="/">
            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
                <soapenv:Header>
                </soapenv:Header>
                <soapenv:Body>
                    <xsl:apply-templates select="/*/*/*"/>
                </soapenv:Body>
            </soapenv:Envelope>
      </xsl:template>
    
      <xsl:template match="*">
        <xsl:param name="pKey" select="local-name()"/>
        <xsl:element name="get:{local-name()}" namespace="{$vParams/*[@name = $pKey]/@ns}">
          <xsl:copy-of select="namespace::*|@*"/>
          <xsl:apply-templates>
            <xsl:with-param name="pKey" select="$pKey"/>
          </xsl:apply-templates>
        </xsl:element>
      </xsl:template>
    </xsl:stylesheet>
    

    将此转换应用于以下XML文档(提供的转换为第二个,具有不同名称的payload子项):

    <request>
        <payload>
            <GetImageRequest>
                <participantId>1191152220010</participantId>
                <participantCode>131029</participantCode>
                <groupCode>027198</groupCode>
                <userType>EE</userType>
                <clientName>Test</clientName>
                <shoeboxID>123444</shoeboxID>
                <imageID>45235</imageID>
            </GetImageRequest>
            <SaveShoeBoxitemRequest>
                <participantId>1191152220010</participantId>
                <participantCode>131029</participantCode>
                <groupCode>027198</groupCode>
                <userType>EE</userType>
                <clientName>Test</clientName>
                <shoeboxID>123444</shoeboxID>
                <imageID>45235</imageID>
            </SaveShoeBoxitemRequest>
        </payload>
    </request>
    

    想要的,正确的(与其他答案中的“解决方案”不同)产生结果

        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
           <soapenv:Header/>
           <soapenv:Body>
              <get:GetImageRequest 
    xmlns:get="urn:webservice/server/mobile/shoebox/types/v1/GetShoeboxItem">
                 <get:participantId>1191152220010</get:participantId>
                 <get:participantCode>131029</get:participantCode>
                 <get:groupCode>027198</get:groupCode>
                 <get:userType>EE</get:userType>
                 <get:clientName>Test</get:clientName>
                 <get:shoeboxID>123444</get:shoeboxID>
                 <get:imageID>45235</get:imageID>
              </get:GetImageRequest>
              <get:SaveShoeBoxitemRequest 
    xmlns:get="urn:webservice/server/mobile/shoebox/types/v1/SaveShoeboxItem">
                 <get:participantId>1191152220010</get:participantId>
                 <get:participantCode>131029</get:participantCode>
                 <get:groupCode>027198</get:groupCode>
                 <get:userType>EE</get:userType>
                 <get:clientName>Test</get:clientName>
                 <get:shoeboxID>123444</get:shoeboxID>
                 <get:imageID>45235</get:imageID>
              </get:SaveShoeBoxitemRequest>
           </soapenv:Body>
        </soapenv:Envelope>
    

答案 1 :(得分:0)

  

所以,如果我知道这5个元素的所有命名空间我可以放在一个   xml文件,可以从该XML文件中检索。或者你提到的可以   在全局文档中定义那些名称空间。

如果你有一个使用哪个命名空间的地图与哪个“root”元素名称,你也可以将它保存在样式表本身。

以下是一个示例(使用虚构的命名空间,因为您没有指定自己的命名空间):

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://www.example.com/my"
exclude-result-prefixes="my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<my:ns-map>
    <ns root="GetImageRequest">urn:webservice/a/b/GetShoeboxItem</ns>
    <ns root="SaveShoeBoxitemRequest">urn:webservice/c/d/SaveShoeBoxitemRequest</ns>
    <ns root="SaveClaimWithReceiptRequest">urn:webservice/e/f/SaveClaimWithReceiptRequest</ns>
    <ns root="GetThumbNailImageRequest">urn:webservice/g/h/GetThumbNailImageRequest</ns>
    <ns root="AttachReceiptwithExistingClaimRequest">urn:webservice/i/k/AttachReceiptwithExistingClaimRequest</ns>
</my:ns-map>

<xsl:variable name="root" select="name(/request/payload/*)"/>
<xsl:variable name="ns" select="document('')/xsl:stylesheet/my:ns-map/ns[@root=$root]"/>

<xsl:template match="/">
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <soapenv:Header/>
        <soapenv:Body>
            <xsl:apply-templates select="request/payload/*" />
        </soapenv:Body>
    </soapenv:Envelope>
</xsl:template>     

<xsl:template match="*" >
    <xsl:element name="get:{local-name()}" namespace="{$ns}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

</xsl:stylesheet>