tags:

views:

1228

answers:

7

Say I have a very simple XML with an empty tag 'B':

<Root>
  <A>foo</A>
  <B></B>
  <C>bar</C>
</Root>

I'm currently using XSLT to remove a few tags, like 'C' for example:

<?xml version="1.0" ?>

<xsl:stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

<xsl:output method="xml" indent="no" encoding="utf-8" omit-xml-declaration="yes" />

<xsl:template match="*">
 <xsl:copy>
  <xsl:copy-of select="@*" />
  <xsl:apply-templates />
 </xsl:copy>
</xsl:template>

<xsl:template match="C" />

</xsl:stylesheet>

So far OK, but the problem is I end up having an output like this:

<Root>
  <A>foo</A>
  <B/>
</Root>

when I actually really want:

<Root>
  <A>foo</A>
  <B></B>
</Root>

Is there a way to prevent 'B' from collapsing?

Thanks.

A: 

No. The 2 are syntactically identical, so you shouldn't have to worry

Brian Agnew
The problem is I'm passing this XML to a third party that does not accept collapsed elements (unfortunatelly).
Tiago Fernandez
It sounds like they've rolled their own XML parser, in that case, and you have to wonder what else they won't accept. Proper character encodings ? Entities etc.?
Brian Agnew
+2  A: 

There is no standard way, as they are equivalent; You might be able to find an XSLT engine that has an option for this behaviour, but I'm not aware of any.

If you're passing this to a third party that cannot accept empty tags using this syntax, then you may have to post-process the output yourself (or convince the third party to fix their XML parsing)

Rowland Shaw
See my comment above. It seems xsl:output method="html" would fix it.
Tiago Fernandez
With some parsers, and some elements, that will completely omit the closing tag altogether; It *can* work, but isn't a general solution
Rowland Shaw
+1 re post processing. If you are outputting XHTML for the web, you still need to have empty elements with a close element for some browsers (e.g. <script... /> has to be <script ... ></script>) so not such an uncommon problem.
Alan Christensen
+2  A: 

It is up to the XSLT engine to decide how the XML tag is rendered, because a parser should see no difference between the two variations. However, when outputting HTML this is a common problem (for <textarea> and <script> tags for example.) The simplest (but ugly) solution is to add a single whitespace inside the tag (this does change the meaning of the tag slightly though.)

Blixt
It could work, but I can't afford modifying the original XML.
Tiago Fernandez
Then your simplest option is to post-process the XSLT. The quick and dirty solution is to make a regex to replace <.../> with <...></...> (which many will frown upon because it's not a solid solution if you want to support any kind of XML.) The other, proper solution is to change the XSLT engine.
Blixt
What about setting the output method as HTML? I quick test I did prevented empty collapsed elements, but I'm not sure about possible side-effects...
Tiago Fernandez
A: 

It should not be a problem if it is or . However if you are using another tool which expects empty XML tags as way only, then you have a problem. A not very elegant way to do this will be adding a space between staring and ending 'B' tags through XSLT code.

Varun Mahajan
As I said above, I can't modify the original XML.
Tiago Fernandez
Another option for you then is write the empty elements through XSLT code like <xsl:text>>B<>/B></xslt:text>
Varun Mahajan
+3  A: 

Ok, so here what worked for me:

<xsl:output method="html">

Thank you all for your help :-)

Tiago Fernandez
Just method="html" and no other change gives <B></B> instead of <B />?
Rashmi Pandit
Yes, that's it.
Tiago Fernandez
A: 
<xsl:text disable-output-escaping="yes">
<![CDATA[<div></div>]]>
</xsl:text>

This works fine with C#'s XslCompiledTransform class with .Net 2.0, but may very well fail almost anywhere else. Do not use unless you are programmatically doing the transofrm yourself; it is not portable at all.

Brian
A: 

This has been a long time issue and I finally made it work with a simple solution. Add <xsl:text/> if you have a space character. I added a space in my helper class. <xsl:choose> <xsl:when test="$textAreaValue=' '"> <xsl:text/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$textAreaValue"/> </xsl:otherwise> </xsl:choose>

Siva