Как заставить явное закрытие тега с помощью Linq XML?

Это тот же вопрос, что и: Явные теги закрытия элементов с пространством System.Xml.Linq

но я использую Net 4.0, и ответы больше не работают.

Проблема заключается в том, что я сохраняю теги без значений, и мой выходной XML выглядит так:

<field/>

Но мне нужно всегда открывать и закрывать тег, т.е.

<field></field>

ВОПРОС: как это сделать?

редактирует

1

Добавление пустых узлов:

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

и позже, сохраняя xml:

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

FullEndingXmlTextWriter - это специализированный класс, на который указывал The Evil Greebo (предполагается, что он использует явный закрывающий тег).

Ответ 1

Я не могу воспроизвести вашу ошибку. Это работает как ожидалось в 4.0 и 3.5 netFX:

namespace ExplicitXmlClosingTags
{
    using System.Xml;
    using System.Xml.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            const string ElementRoot = "RootElement";
            const string ElementChild = "ChildElement";
            const string AttributeChild = "ChildAttribute";

            XDocument xDoc = new XDocument();
            XElement root = new XElement(ElementRoot);
            XElement child = new XElement(ElementChild, string.Empty);
            root.Add(child);

            child.SetAttributeValue(AttributeChild, "AttrValue");
            xDoc.Add(root);

            XmlWriterSettings xws = new XmlWriterSettings();
            xws.Indent = true;
            using (XmlWriter xw = XmlWriter.Create("out.xml", xws))
            {
                xDoc.Save(xw);    
            }
        }
    }
}

создавая следующий контент:

<?xml version="1.0" encoding="utf-8"?>
<RootElement>
  <ChildElement ChildAttribute="AttrValue"></ChildElement>
</RootElement>

Ответ 2

Явная установка значения XElement в пустую строку должна работать. LINQ-to-XML уже обрабатывает узлы без содержимого (например, new XElement("foo")) по-разному от узлов с содержанием нулевой длины (например, new XElement("foo", string.Empty)), как вы можете видеть из документации по XElement.IsEmpty.

Но в случае, если это не сработает, или если вам нужно точно настроить какой-либо другой аспект выхода XML, вы можете получить пользовательский 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; }
    }
}

Соответствующий метод:

public override void WriteEndElement()
{
    inner.WriteFullEndElement(); // always write both start and close tags
}

Ответ 3

установите значение XElement в String.Empty

ИЛИ

установив для свойства IsEmpty значение false для всех элементов, не имеющих дочерних узлов

    foreach (XElement childElement in
        from x in document.DescendantNodes().OfType<XElement>()
        where x.IsEmpty
        select x)
    {
        childElement.IsEmpty = false;
    }

Ответ 4

 var document = XDocument.Parse(XMLData); 
                        foreach (XElement childElement in
                        from x in document.DescendantNodes().OfType<XElement>()
                        where x.IsEmpty
                        select x)
                        {
                            childElement.Value = "";
                        }

Попробуйте эту работу. Просто замените childElement.IsEmpty = false; на childElement.Value = "";