问题 当没有数据时,防止XmlSerializer中的自闭标签


当我序列化值时:如果数据中没有值,那么它就像下面的格式一样。

  <Note>
        <Type>Acknowledged by PPS</Type>
        <Data />
  </Note>

但我想要的xml数据格式如下:

  <Note>
        <Type>Acknowledged by PPS</Type>
        <Data></Data>
  </Note>

代码为此我写了:

[Serializable]
public class Notes
{
    [XmlElement("Type")]
    public string typeName { get; set; }

    [XmlElement("Data")]
    public string dataValue { get; set; }
}

如果数据没有分配任何值,我无法弄清楚如何以下面的格式实现数据。

  <Note>
        <Type>Acknowledged by PPS</Type>
        <Data></Data>
  </Note>

9501
2017-11-24 08:18


起源

虽然我不确定你为什么要这样做,但请注意你写的xml实际上是无效的。您永远不会关闭数据元素。 - Yuriy Faktorovich
如果我使用它,那么[XmlElementAttribute(IsNullable = false)] <Data> </ Data>完全忽略我不想要的 - Nishant Kumar
<Da​​ta />和<Data> </ Data>之间的差异实际上很重要的时间很短,通常直接与不完整/错误的实现相关联。你为什么要这个? - Marc Gravell♦
因为如果在<Data> </ Data>值中找不到元素,我正在进行一些操作 - Nishant Kumar
你应该阅读我的回答 这个问题 并将其应用于您的情况。 - Grzegorz W


答案:


您可以通过创建自己的XmlTextWriter来传递进入序列化过程。

public class MyXmlTextWriter : XmlTextWriter
{
    public MyXmlTextWriter(Stream stream) : base(stream, Encoding.UTF8)
    {

    }

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

您可以使用以下方法测试结果:

class Program
{
    static void Main(string[] args)
    {
        using (var stream = new MemoryStream())
        {
            var serializer = new XmlSerializer(typeof(Notes));
            var writer = new MyXmlTextWriter(stream);
            serializer.Serialize(writer, new Notes() { typeName = "Acknowledged by PPS", dataValue="" });
            var result = Encoding.UTF8.GetString(stream.ToArray());
            Console.WriteLine(result);
        }
       Console.ReadKey();
    }

9
2017-11-24 10:47



注意:这将导致 null -> "" 何时序列化/反序列化。
工作,但然后生成的XML在每个元素后没有换行:( - SuperJMN
@SuperJMN你需要环绕一个 XmlWriter。潜在的 XmlWriter 需求 XmlWriterSettings 同 Indent 设置 true 和 NewLineChars 设置一些明智的东西。例: pastebin.com/G2bZNQnQ (也适用于 Stream 代替 TextWriter) - domi1819
伤心但不起作用...... :( - Tommix
它在缩进模式下有一个包。这个 stackoverflow.com/a/40423636/4594225 为我工作。 - Ali


IMO不可能使用生成所需的XML Serialization。但是,你可以使用 LINQ to XML 生成这样的所需模式 -

XDocument xDocument = new XDocument();
XElement rootNode = new XElement(typeof(Notes).Name);
foreach (var property in typeof(Notes).GetProperties())
{
   if (property.GetValue(a, null) == null)
   {
       property.SetValue(a, string.Empty, null);
   }
   XElement childNode = new XElement(property.Name, property.GetValue(a, null));
   rootNode.Add(childNode);
}
xDocument.Add(rootNode);
XmlWriterSettings xws = new XmlWriterSettings() { Indent=true };
using (XmlWriter writer = XmlWriter.Create("D:\\Sample.xml", xws))
{
    xDocument.Save(writer);
}

主要的是 in case your value is null, you should set it to empty string。它会 force the closing tag to be generated。如果value为null,则不会创建结束标记。


1
2017-11-24 10:19





Kludge时间 - 见 生成在HTML中有效的System.Xml.XmlDocument.OuterXml()输出

基本上,在生成XML doc后,遍历每个节点,如果没有子节点,则添加一个空文本节点

// Call with
addSpaceToEmptyNodes(xmlDoc.FirstChild);

private void addSpaceToEmptyNodes(XmlNode node)
{
    if (node.HasChildNodes)
    {
        foreach (XmlNode child in node.ChildNodes)
            addSpaceToEmptyNodes(child);
    }
    else         
        node.AppendChild(node.OwnerDocument.CreateTextNode(""))
}

(是的,我知道您不应该这样做 - 但如果您将XML发送到其他一些您无法轻易解决的系统,那么必须务必做事)


0
2017-12-11 21:38



我不得不改变 if (node.HasChildNodes) 至 if (node.HasChildNodes && node.NodeType != XmlNodeType.Text) - BurnsBA


您可以添加虚拟字段以防止自闭合元素。

[XmlText]
public string datavalue= " ";

或者如果你想要你的类的代码,那么你的类应该是这样的。

public class Notes
{
   [XmlElement("Type")]
   public string typeName { get; set; }

   [XmlElement("Data")]
   private string _dataValue;
   public string dataValue {
      get {
          if(string.IsNullOrEmpty(_dataValue))
             return " ";
          else
             return _dataValue;
      }
      set {
          _dataValue = value;
      }
   }
}

0
2017-12-05 11:41



“”仍然是有价值的。 - Tommix