2

I'm trying to convert XML that is passed in, but retain the original xml in a new node.

Let's say the following XML is being transformed.

<Document>
   <Number>12345</Number>
   <Name>Person Name</Name>
</Document>

My desired output is this:

<Document>
   <Number>12345</Number>
   <OriginalXml>
       <![CDATA[
           ^^ the above xml ^^
       ]]
   </OriginalXml>
</Document>

I did in C# easily, but the dev manager wanted to see if it's doable in XSLT.

Thanks.

  • I'm not really strong in xslt. Our current xslt transforms the xml document as needed. I just need to find out if it's possible to add in the untransformed xml in a new OriginalXml node. – user1569663 Aug 01 '12 at 20:30
  • 1
    Is there a (valid) requirement for CDATA in the output? If the original XML is well-formed , what is the point of using CDATA? – Mads Hansen Aug 01 '12 at 23:58
  • Is it really a requirement that you retain not the original XML, but an escaped version of it? (e.g. using CDATA) If the requirement is to escape the original XML, then try http://stackoverflow.com/questions/11620147/output-entire-xml-as-an-attribute#comment15406773_11620147 – LarsH Aug 02 '12 at 01:10
  • We're storing the Xml in the database. We're storing the original xml in the database. Therefore we need it to be un-escaped. – user1569663 Aug 02 '12 at 14:40

1 Answers1

3

You could do something like this:

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="/Document">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <OriginalXml>
                <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
                <xsl:copy-of select="."/>
                <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
            </OriginalXml>      
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Name"/>

</xsl:stylesheet>

Output

<Document>
   <Number>12345</Number>
   <OriginalXml>
      <![CDATA[<Document>
         <Number>12345</Number>
         <Name>Person Name</Name>
      </Document>]]>
   </OriginalXml>
</Document>
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
  • Nice example of applying the XSLT identity transform which is provided by Visual Studio when one creates a new XSLT file. – Mihai Todor Aug 01 '12 at 22:19
  • 2
    @MihaiTodor - Thank you. The XSLT template I use in oXygen also has the identity transform by default. I use it in almost every stylesheet. – Daniel Haley Aug 01 '12 at 22:21
  • 1
    Clever, yet evil use of D-O-E! – LarsH Aug 02 '12 at 01:09
  • @LarsH - It felt so wrong using D-O-E. I try to avoid it like the plague ;-) – Daniel Haley Aug 02 '12 at 05:37
  • I will test and let you know if I get it to work. I'll mark your answer as correct afterwards if all is good. Thanks :) – user1569663 Aug 02 '12 at 14:38
  • When I'm doing the copy-of, I'm getting the error Unexpected tlken 'eof' in the expression. – user1569663 Aug 02 '12 at 15:18
  • @user1569663 - Are you using an exact copy of the example XSLT? If so, something might've been dropped in the copy/paste. If not, can you post your `xsl:copy-of` (or more XSLT)? It *should* be obvious. – Daniel Haley Aug 02 '12 at 15:59
  • nevermind, got it to work. I was trying to show the xml in a subnode rather than showing it in the parent node, which didn't work by doing copy-of ../. Instead I created a variable in the parent node and populated the value in the subnode using the variable. That worked and got rid of the error. Thanks!!! – user1569663 Aug 02 '12 at 16:40
  • @user1569663 - You could also change your xsl:copy-of to ``. That should work from anywhere. You're very welcome! Glad it worked for you. – Daniel Haley Aug 02 '12 at 17:05