Как заставить явное закрытие тега с помощью 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 = ""
;