【问题标题】:Render empty XML elements like <this />, not <this></this> when using Save() on XmlDocument在 XmlDocument 上使用 Save() 时呈现空的 XML 元素,例如 <this />,而不是 <this></this>
【发布时间】:2011-06-30 12:24:30
【问题描述】:

我有一个 .NET C# 解决方案,它可以构建复杂的 XmlDocument,然后将其通过网络传输到外部 API。由于 API 中令人讨厌的怪癖,我需要能够渲染空元素,例如:

<empty />

不是这样(默认情况下似乎会发生):

<empty></empty>

在这种情况下,我们使用 .NET XmlDocument 对象并准备将其作为 HttpWebRequest 的一部分发送,我将 XML 文档写入字节数组,代码如下:

MemoryStream ms = new MemoryStream();
xmlDoc.Save(ms);
ms.Position = 0;
byte[] postData = new byte[ms.Length];
ms.Read(postData, 0, postData.Length);
ms.Close();

postData 然后使用以下命令写入 Web 请求:

webRequest.GetRequestStream().Write(postData, 0, postData.Length);

谢谢!

【问题讨论】:

    标签: .net xml


    【解决方案1】:

    XmlDocument 保留了在加载其 XML 时定义元素的方式 - 如果输入有空元素,它将按原样输出它们,如果它们是 Element/EndElement,它也将保持这些元素。您可以预处理 XmlDocument 节点,可以使用一个简单的递归函数(如下所示)。

    public class StackOverflow_6529793
    {
        public static void Test()
        {
            XmlDocument doc = new XmlDocument();
            string xml = "<root><item1></item1><item2></item2><item3/><item4 a='b'></item4><a:item5 xmlns:a='ns'></a:item5></root>";
            doc.LoadXml(xml);
            MemoryStream ms = new MemoryStream();
            doc.Save(ms);
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    
            CollapseEmptyElements(doc.DocumentElement);
            ms = new MemoryStream();
            doc.Save(ms);
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
        }
        static void CollapseEmptyElements(XmlElement node)
        {
            if (!node.IsEmpty && node.ChildNodes.Count == 0)
            {
                node.IsEmpty = true;
            }
    
            foreach (XmlNode child in node.ChildNodes)
            {
                if (child.NodeType == XmlNodeType.Element)
                {
                    CollapseEmptyElements((XmlElement)child);
                }
            }
        }
    }
    

    【讨论】:

    • 很好的解决方案!顺便说一句,您可以使用node.HasChildNodes 而不是node.ChildNodes.Count == 0
    • 谢谢,效果很好。在我的特定场景中,它并没有折叠某些确实具有子节点的元素,该子节点只是一个空文本元素。我可以通过将测试更改为 if (!node.IsEmpty &amp;&amp; (node.ChildNodes.Count == 0 || (node.ChildNodes.Count == 1 &amp;&amp; node.ChildNodes[0].NodeType == XmlNodeType.Text &amp;&amp; string.IsNullOrEmpty(node.ChildNodes[0].InnerText)))) 来调整您的代码
    【解决方案2】:

    您可能知道,XML 标准规定 &lt;empty /&gt;&lt;empty&gt;&lt;/empty&gt; 完全等价,因此 XmlDocument 对象没有做错任何事情。

    您可能会做的是通过过滤器(可能是正则表达式)运行生成的 XML,以将非最小化标记的实例更改为最小化标记形式。然后,将过滤后的带有最小化标签的 XML 发送到webRequest

    【讨论】:

    • 你和我都知道这一点,而为他们的旧 CRM 系统构建 API 的轻量级人员却不知道。
    猜你喜欢
    • 2020-01-17
    • 2011-01-28
    • 2023-03-30
    • 2016-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多