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


11490
2018-06-15 08:45


起源

为什么这有关系? - Dan Diplo
@Dan软件“吃”这可能是小马车,并没有正确处理这种语法,我也一直在这种情况下。一般来说是的,这应该不重要。 - Petr Abdulin


答案:


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

5
2018-06-16 15:24



(谢谢您的回答)。现在 IS 有趣。我复制并粘贴了你的例子,我做了 不 有明确的结束标签(我也试过.Net 3.5)。 Geee,兼容性...... - greenoldman


明确地设定 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
}

8
2018-06-15 09:54



Martinho在这里谈论的类似例子: stackoverflow.com/questions/1849214/...  我有同样的问题 - 我有一个黑盒子应用程序,需要完整形成的XML和使用修改后的XmlWriter工作得很好,以确保永远不会发送合同空标签。 - The Evil Greebo
谢谢你的想法(顺便说一句。你的代码编写错误 - 同时你继承并编写XmlWriter,实际上你应该继承,只覆盖构造函数和相关方法),但是...我是一个不幸的家伙,它仍然没有按预期工作。我在原帖中加了一个编辑。 - greenoldman
@macias:继承+组合是故意的。我写的MyWriter是一个 装饰。它适用于任何XmlWriter,而不仅仅适用于XmlTextWriter。我完全按原样测试它,它的工作原理。我想要获得XmlWriter的现有实现,并继承暴露相同的接口。 - R. Martinho Fernandes
那么你应该从泛型类继承哪个基类是XmlWriter。从另一个类继承并且不使用它,并且同时编写是一个坏主意(一般来说,它可能比这里更糟糕,因为构造函数可能是非平凡的)。 - greenoldman


设置的值 XElement 至 String.Empty

要么

设置 IsEmpty 财产 false 对于没有任何子节点的所有元素

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

2
2018-06-15 08:48



我做了,这是上一篇文章的答案,但它不起作用。 - greenoldman
编辑的答案显示另一种方法,设置 IsEmpty 至 false。 - harryovers
你编译了这段代码?因为这里我得到了非常期望的消息错误,所以IsEmpty是只读属性。好奇你是怎么做到的:-) - greenoldman
大声笑,好抓:) - harryovers
@greenoldman你可以做什么,我测试它,正在将值更改为string.Empty,它也明确关闭XML元素 - Lukas Huzen


 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 = "";


-1
2017-09-21 10:02