XSLT to copy elements from source into CDATA section
Asked Answered
D

2

5

I am transforming a simple SOAP XML message into a more extended SOAP XML message. I got it almost to work, but I can't manage to fix the last 2 issues. My issues are:

  1. All elements after the element should be in a CDATA section. I tried to use 'cdata-section-elements', but can't get it working.
  2. Element should look like this

My Source XML file:

<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <test>
      <element1>123</element1>
      <element2>123</element2>
    </test>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

My XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" exclude-result-prefixes="fn xs SOAP-ENV">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />

<!-- Special rule to match the document root only -->
<xsl:template match="/*">
    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
        <xsl:namespace name="a" select="'http://www.w3.org/2005/08/addressing'"/>
        <xsl:apply-templates select="@*|node()"/>
    </s:Envelope>
</xsl:template>

<!-- Expand soap header -->
<xsl:template match="SOAP-ENV:Header">
    <xsl:element name="s:{local-name()}" namespace="http://www.w3.org/2003/05/soap-envelope">
        <xsl:element name="a:Action" namespace="http://www.w3.org/2005/08/addressing">
            <xsl:attribute name="s:mustUnderstand" namespace="http://www.w3.org/2003/05/soap-envelope">1</xsl:attribute>
            <xsl:text>http://www.ortec.com/CAIS/IApplicationIntegrationService/SendMessage</xsl:text>
        </xsl:element>
    </xsl:element>
</xsl:template>

<!-- Change soap body -->
<xsl:template match="SOAP-ENV:Body">
    <xsl:element name="s:{local-name()}" namespace="http://www.w3.org/2003/05/soap-envelope">
        <xsl:element name="cais:SendMessage" namespace="http://www.ortec.com/CAIS">
            <xsl:element name="cais:message" namespace="http://www.ortec.com/CAIS">
                <!-- copy the rest -->
                <xsl:apply-templates select="child::node()"/>
            </xsl:element>
            <xsl:element name="cais:commandName" namespace="http://www.ortec.com/CAIS">Import</xsl:element>
        </xsl:element>
    </xsl:element>
</xsl:template>

<!-- template for the copy of the rest -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

The WRONG output I receive now with this XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://www.ortec.com/CAIS/IApplicationIntegrationService/SendMessage</a:Action>
  </s:Header>
  <s:Body>
    <cais:SendMessage xmlns:cais="http://www.ortec.com/CAIS">
      <cais:message>
        <test xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
          <element1>123</element1>
          <element2>123</element2>
        </test>
      </cais:message>
      <cais:commandName>Import</cais:commandName>
    </cais:SendMessage>
  </s:Body>
</s:Envelope>

My DESIRED output:

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://www.ortec.com/CAIS/IApplicationIntegrationService/SendMessage</a:Action>
  </s:Header>
  <s:Body>
    <cais:SendMessage xmlns:cais="http://www.ortec.com/CAIS">
      <cais:message>
        <![CDATA[
        <test>
          <element1>123</element1>
          <element2>123</element2>
        </test>
        ]]>
      </cais:message>
      <cais:commandName>Import</cais:commandName>
    </cais:SendMessage>
  </s:Body>
</s:Envelope>
Danseuse answered 13/2, 2013 at 10:19 Comment(1)
+1, well-documented question! If only all XSLT questions included input XML, attempted XSLT, desired output, and actual output.Tungstic
W
8

Might the following work?:

<xsl:template match="SOAP-ENV:Body">
    <xsl:element name="s:{local-name()}" namespace="http://www.w3.org/2003/05/soap-envelope">
        <xsl:element name="cais:SendMessage" namespace="http://www.ortec.com/CAIS">
            <xsl:element name="cais:message" namespace="http://www.ortec.com/CAIS">
                <!-- copy the rest -->
                <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
                <xsl:apply-templates select="child::node()"/>
                <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
            </xsl:element>
            <xsl:element name="cais:commandName" namespace="http://www.ortec.com/CAIS">Import</xsl:element>
        </xsl:element>
    </xsl:element>
</xsl:template>

When I modify the XSLT in this way and run it on your sample input, I get:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header><a:Action s:mustUnderstand="1" xmlns:a="http://www.w3.org/2005/08/addressing">http://www.ortec.com/CAIS/IApplicationIntegrationService/SendMessage</a:Action></s:Header>
  <s:Body><cais:SendMessage xmlns:cais="http://www.ortec.com/CAIS"><cais:message>
  <![CDATA[
    <test xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <element1>123</element1>
      <element2>123</element2>
    </test>
  ]]>
  </cais:message>
  <cais:commandName>Import</cais:commandName></cais:SendMessage></s:Body>
</s:Envelope>

The namespace declaration is still there, but that shouldn't really matter.

If you really want to get rid of the namespace declaration on <test>, you can replace your identity template with this:

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

  <xsl:template match="*">
    <xsl:element name="{name()}">
      <xsl:apply-templates select="@* | node()" />
    </xsl:element>
  </xsl:template>

I've verified that that seems to work.

And just as a side note, if you know the prefix and name of your elements ahead of time, you don't need to use xsl:element or namespace attributes. If you declare your namespaces in the xsl:spreadsheet element:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                   xmlns:fn="http://www.w3.org/2005/xpath-functions" 
                   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
                   xmlns:s="http://www.w3.org/2003/05/soap-envelope"
                   xmlns:cais="http://www.ortec.com/CAIS"
                   exclude-result-prefixes="fn xs SOAP-ENV cais">

Then you can just do this:

<xsl:template match="SOAP-ENV:Body">
    <xsl:element name="s:{local-name()}">
        <cais:SendMessage>
            <cais:message>
                <!-- copy the rest -->
                <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
                <xsl:apply-templates select="child::node()"/>
                <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
            </cais:message>
            <cais:commandName>Import</cais:commandName>
        </cais:SendMessage>
    </xsl:element>
</xsl:template>
Wellhead answered 13/2, 2013 at 10:57 Comment(4)
Thanks this solves the first problem about the CDATA. Still struggling with the namespace in element <test>.Danseuse
@MarkVeenstra Added a suggestion for getting rid of the namespace declaration.Wellhead
Glad to help. If this solved all your questions, please remember to click the checkmark icon next to this answer. Thank you!Wellhead
Now my reputation is high enough I just upvoted your answer so you will gain some reputation as well. Thanks again!Danseuse
C
1

Use copy-namespace="no" with xsl:copy-of element to avoid bounding of namespace in test element:

<xsl:template match="SOAP-ENV:Body">
 <xsl:element name="s:{local-name()}">
   <xsl:element name="cais:SendMessage">
   <xsl:element name="cais:message">
   <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
   <xsl:copy-of select="test" copy-namespaces="no"/>
   <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
  </xsl:element>
  <xsl:element name="cais:commandName"><xsl:text>Import</xsl:text>
</xsl:element>
  </xsl:element>
 </xsl:element>
</xsl:template>
</xsl:stylesheet>
Crystallite answered 13/7, 2016 at 10:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.