tags:

views:

577

answers:

2

System.Xml.XmlDocument.OuterXml() will generate (for example)

<list id="myBooks">
  <book id="123" name="XML for muppets" />
  <book id="456" name="HTML for fools" />
</list>

If you want to embed this xml into HTML page then it will work fine in IE (as xml data islands are an extension to the html standards)

However for Firefox you need to load this unknown html tag that happens to contain xml into a DOMParser using something like

var list = document.getElementById("myBooks");
var doc = new DOMParser().parseFromString(list.outerHTML);

However because <tag /> is not == <tag></tag> in HTML firefox will see list.outerHTML as

<list>
  <book id="123" name="XML for muppets">
     <book id="456" name="HTML for fools">
     </book>
  </book>
</list>

So how do I get XmlDocument.OuterXml() to output xml will full closing tags rather than shorthand ?

EDIT - Added example to illustrate

<html><body>
<xml id="myBooks">
<list>
  <book id="123" name="XML for muppets" />
  <book id="456" name="HTML for fools" />
</list>
</xml>
<script>
var oXml = document.getElementById("myBooks");
alert(oXml.innerHTML);
</script>
</body></html>
+2  A: 

I am confused. What makes you think Firefox will not be able to interpret the self-closing XML tags? XHTML which is supported by every major browser including Firefox, allows you to use such self-closing tags anywhere that you don't have content. Why would an XML data island be any different?

Additionally, you may want to look at using XmlTextWriter to write to a StringWriter or something. You can configure an XmlTextWriter with an XmlWriterSettings that specifies an XmlOutputMethod of Html that may provide more HTML-like output.

UPDATE Unfortunately I just tested this and OutputMethod property has an internal setter. But out of curiosity I used reflection to set it and it did in fact change the XML output such that the self-closing tags were turned into separate close tags. Code is below.

var stream = new System.IO.StringWriter();
var xmldoc = new System.Xml.XmlDocument();
xmldoc.LoadXml("<root><child><grandchild /></child><child /></root>");

var settings = new System.Xml.XmlWriterSettings();
var propInfo = settings.GetType().GetProperty("OutputMethod");
propInfo.SetValue(settings, System.Xml.XmlOutputMethod.Html, null);
var writer = System.Xml.XmlWriter.Create(stream, settings);

xmldoc.Save(writer);

stream.ToString().Dump();
Josh Einstein
What make me think it doesnt - well a test ;)See edit with example.
Ryan
Sorry didn't mean to sound like I doubted you - but that sure sounds like a bug for FireFox to be ignoring the self-closing tag like that especially if you're seeing the same behavior in an XHTML page.
Josh Einstein
No worries - I am doubting myself right now!
Ryan
I was battling with this until the early hours - why-oh-why does .OutputMethod have an internal setter? Using reflection is not going to work for me I think (CAS) so I've come up with the kludge below.
Ryan
+1  A: 

This is a bit of a kludge, but adds a space into any empty nodes so would change

<book id="123" name="XML for muppets" />

into

<book id="123" name="XML for muppets"> </book>

Looking forward to appearing on DailyWTF!

addSpaceToEmptyNodes(xmlDoc.FirstChild);

private void addSpaceToEmptyNodes(XmlNode node)
    {
        if (node.HasChildNodes)
        {
            foreach (XmlNode child in node.ChildNodes)
                addSpaceToEmptyNodes(child);
        }
        else         
            node.InnerText = " ";
    }
Ryan
Out of curiosity I found that you can similarly get the output you desire without changing the XML to have a space in the text node. Do the same thing you're doing except instead of node.InnerText = " ", do node.AppendChild(node.OwnerDocument.CreateTextNode("")). That way the document will be structurally equal.
Josh Einstein