【问题标题】:Prevent self closing tags in XmlSerializer when no data is present不存在数据时防止 XmlSerializer 中的自闭合标记
【发布时间】:2012-11-24 08:18:51
【问题描述】:

当我序列化值时:如果数据中没有值,那么它的格式如下所示。

  <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>

【问题讨论】:

  • 虽然我不确定您为什么要这样做,但请注意您编写的 xml 实际上是无效的。您永远不会关闭 Data 元素。
  • 如果我使用它,那么 [XmlElementAttribute(IsNullable = false)] 完全忽略我不想要的
  • 之间的差异实际上很重要的时间很小,并且通常直接与不完整/错误的实现相关联。你为什么要这个?
  • 因为如果在 值中找不到元素,我正在做一些操作
  • 您应该阅读我对this question 的回答并将其应用于您的情况。

标签: c# .net xml


【解决方案1】:

您可以通过创建自己的 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();
    }

【讨论】:

  • 注意:这将在序列化/反序列化时导致null -&gt; ""
  • 有效,但随后生成的 XML 没有在每个元素后换行 :(
  • @SuperJMN 您需要环绕 XmlWriter。底层XmlWriter 需要XmlWriterSettingsIndent 设置为trueNewLineChars 设置为合理的值。示例:pastebin.com/G2bZNQnQ(也适用于 Stream 而不是 TextWriter
  • 它有一个缩进模式的包。这个stackoverflow.com/a/40423636/4594225 为我工作。
【解决方案2】:

IMO 不可能使用 Serialization 生成所需的 XML。但是,您可以使用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。如果值为 null,则不创建结束标记。

【讨论】:

    【解决方案3】:

    混搭时间 - 见Generate System.Xml.XmlDocument.OuterXml() output thats valid in HTML

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

    // 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 发送到您无法轻松修复的其他系统,则必须务实)

    【讨论】:

    • 我不得不将 if (node.HasChildNodes) 更改为 if (node.HasChildNodes &amp;&amp; node.NodeType != XmlNodeType.Text)
    【解决方案4】:

    您可以添加一个虚拟字段来防止自动关闭元素。

    [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;
          }
       }
    }
    

    【讨论】:

    • " " 仍然是值。
    【解决方案5】:

    原则上,armen.shimoon's answer 为我工作。但是,如果您希望在不使用 XmlWriterSettings 和额外的 Stream 对象(如 cmets 中所述)的情况下漂亮地打印 XML 输出,您可以简单地在 XmlTextWriter 类的构造函数中设置 Formatting。

    public MyXmlTextWriter(string filename) : base(filename, Encoding.UTF8)
    {
        this.Formatting = Formatting.Indented;
    }
    

    (会将此作为评论发布,但目前还不允许;-))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-10
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      相关资源
      最近更新 更多