views:

38

answers:

3

How can I have XSLT wrap input XML within a parent node, only if it doesn't already exist?

For example, if my input is:

<Project>...</Project>

I want to wrap it with a prefix and a suffix:

<?xml version "1.0" encoding="utf-8">
<Site>
  <Project>...</Project>
</Site>

If however, <Project> is not the root node of the input, I'd like the input to be left unmodified.

Thanks in advance!

A: 

If adding only the prefix and suffix is your requirement then you can look for other Unix options like grep which can do this much simpler. If you want to do this in XSL then you shuld use xsl:when

<xsl:template match="/">
         <xsl:choose>       <!-- If Node Period exists add the text -->         <xsl:when test="Period">
                        <xsl:text><Site></xsl:text>
                        <xsl:text>&#xa;</xsl:text>
                        <xsl:text><Site></xsl:text>
            </xsl:when>     </xsl:choose>   <xsl:apply-templates select="Notification"/> </xsl:template>
Raghuram
Thanks for the answer. I had difficulty getting it to work, I'm sorry.
DJC
+3  A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/Project">
        <Site>
            <xsl:call-template name="identity"/>
        </Site>
    </xsl:template>
</xsl:stylesheet>

Input 1:

<Project>...</Project>

Output 1:

<Site>
    <Project>...</Project>
</Site>

Input 2:

<Root>
    <Project>...</Project>
</Root>

Output 2:

<Root>
    <Project>...</Project>
</Root>

Note: Identity transformation. Pattern matching

Alejandro
Perfect drop in solution for my specific problem, thank you.
DJC
@DJC: Your are wellcome! Ask any time.
Alejandro
+1  A: 

This transformation:

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

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

 <xsl:template match="*[not(self::site)]/Project">
  <site>
    <xsl:call-template name="identity"/>
  </site>
 </xsl:template>
</xsl:stylesheet>

wraps the element <Project> only when it is not already a child of a <site> element.

When applied on this XML document:

<t>
  <Project>x</Project>
    <site>
      <Project>y</Project>
    </site>
</t>

the correct, wanted result is produced:

<t>
   <site>
      <Project>x</Project>
   </site>
   <site>
      <Project>y</Project>
   </site>
</t>
Dimitre Novatchev
@Dimitre: From the question: "<Project> is not the root node of the input, I'd like the input to be left unmodified"
Alejandro
A useful answer for my toolbox, particularly the not match, thanks!
DJC