Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you force explicit tag closing with Linq XML?

Tags:

c#

xml

linq

tags

This is the same question as: Explicit Element Closing Tags with System.Xml.Linq Namespace

but I use Net 4.0 and the answers do not work anymore.

The problem is I save tags with no values really, and my output XML looks like this:

<field/>

But what I need is always opening and closing tag, i.e.

<field></field>

QUESTION: how to do it?

Edits

1

Adding empty nodes:

if (field_xml == null) // always true, because I create the file for the first time
{
    field_xml = new XElement(XMLKeys.field,String.Empty);
    table_xml.Add(field_xml);
}
field_xml.SetAttributeValue(XMLKeys.name, field_info.Name);
// ... setting some other attributes of this node

and later, saving the xml:

var writer = new FullEndingXmlTextWriter(parameters.OutputFilename, Encoding.UTF8);
root_xml.Save(writer);

FullEndingXmlTextWriter is the specialized class which The Evil Greebo pointed out (it is supposed to force explicit closing tag).

like image 643
greenoldman Avatar asked Jun 15 '11 08:06

greenoldman


People also ask

How do I close a tag in XML?

The end tag functions exactly like a right parenthesis or a closing quotation mark or a right curly brace. It contains no data of its own; it simply ends the most recent (innermost) tag with the same name. XML requires a matching end tag for each start tag.

Does XML have a closing tag?

All XML elements must have a closing tag. XML tags are case sensitive. All XML elements must be properly nested. All XML documents must have a root element.

What is LINQ to XML?

LINQ to XML is a LINQ-enabled, in-memory XML programming interface that enables you to work with XML from within the . NET programming languages. LINQ to XML is like the Document Object Model (DOM) in that it brings the XML document into memory.


1 Answers

Explicitly setting the XElement value to an empty string should work. LINQ-to-XML already treats nodes without content (like new XElement("foo")) differently from nodes with content of length zero (like new XElement("foo", string.Empty)), as you can see from the documentation on XElement.IsEmpty.

But in case that doesn't work, or in case you need to fine tune some other aspect of the XML output, you can derive a custom XmlWriter:

public class MyWriter : XmlWriter
{
    private readonly XmlWriter inner;
    public MyWriter(XmlWriter inner)
    {
        this.inner = inner;
    }

    public void Dispose()
    {
        ((IDisposable) inner).Dispose();
    }

    public override void WriteStartDocument()
    {
        inner.WriteStartDocument();
    }

    public override void WriteStartDocument(bool standalone)
    {
        inner.WriteStartDocument(standalone);
    }

    public override void WriteEndDocument()
    {
        inner.WriteEndDocument();
    }

    public override void WriteDocType(string name, string pubid, string sysid, string subset)
    {
        inner.WriteDocType(name, pubid, sysid, subset);
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        inner.WriteStartElement(prefix, localName, ns);
    }

    public override void WriteEndElement()
    {
        inner.WriteFullEndElement();
    }

    public override void WriteFullEndElement()
    {
        inner.WriteFullEndElement();
    }

    public override void WriteStartAttribute(string prefix, string localName, string ns)
    {
        inner.WriteStartAttribute(prefix, localName, ns);
    }

    public override void WriteEndAttribute()
    {
        inner.WriteEndAttribute();
    }

    public override void WriteCData(string text)
    {
        inner.WriteCData(text);
    }

    public override void WriteComment(string text)
    {
        inner.WriteComment(text);
    }

    public override void WriteProcessingInstruction(string name, string text)
    {
        inner.WriteProcessingInstruction(name, text);
    }

    public override void WriteEntityRef(string name)
    {
        inner.WriteEntityRef(name);
    }

    public override void WriteCharEntity(char ch)
    {
        inner.WriteCharEntity(ch);
    }

    public override void WriteWhitespace(string ws)
    {
        inner.WriteWhitespace(ws);
    }

    public override void WriteString(string text)
    {
        inner.WriteString(text);
    }

    public override void WriteSurrogateCharEntity(char lowChar, char highChar)
    {
        inner.WriteSurrogateCharEntity(lowChar, highChar);
    }

    public override void WriteChars(char[] buffer, int index, int count)
    {
        inner.WriteChars(buffer, index, count);
    }

    public override void WriteRaw(char[] buffer, int index, int count)
    {
        inner.WriteRaw(buffer, index, count);
    }

    public override void WriteRaw(string data)
    {
        inner.WriteRaw(data);
    }

    public override void WriteBase64(byte[] buffer, int index, int count)
    {
        inner.WriteBase64(buffer, index, count);
    }

    public override void Close()
    {
        inner.Close();
    }

    public override void Flush()
    {
        inner.Flush();
    }

    public override string LookupPrefix(string ns)
    {
        return inner.LookupPrefix(ns);
    }

    public override WriteState WriteState
    {
        get { return inner.WriteState; }
    }
}

The relevant method is this one:

public override void WriteEndElement()
{
    inner.WriteFullEndElement(); // always write both start and close tags
}
like image 185
R. Martinho Fernandes Avatar answered Nov 05 '22 23:11

R. Martinho Fernandes