如何使用Linq XML强制显式标记关闭?

这与以下问题相同: 使用System.Xml.Linq命名空间的显式元素关闭标记

但我使用Net 4.0,答案不再适用。

问题是我保存标签没有真正的值,我的输出XML看起来像这样:

但我需要的是始终打开和关闭标签,即

问题 :怎么做?

编辑

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是Evil Greebo指出的专门类(它应该强制显式关闭标记)。

我无法重现你的错误。 这在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); } } } } 

产生以下内容:

     

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 } 

XElement的值设置为String.Empty

要么

对于没有任何子节点的所有元素,将IsEmpty属性设置为false

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

试试这个吧。 只需替换childElement.IsEmpty = false; with childElement.Value = "" ;