【问题标题】:Instruct XmlWriterSettings to use self-closing tags指示 XmlWriterSettings 使用自闭合标签
【发布时间】:2012-04-06 18:55:20
【问题描述】:

我正在使用 XmlWriterSettings 将 Xml 写入文件。我的元素只有属性,没有子元素。我希望它们输出为:

<element a="1" /> 

而不是

<element a="1"></element>

我可以用 XmlWriterSettings 做吗?

编辑:

代码如下:

private void Mission_Save(string fileName)
    {
        StreamWriter streamWriter = new StreamWriter(fileName, false);
        streamWriter.Write(Mission_ToXml());
        streamWriter.Close();
        streamWriter.Dispose();

        _MissionFilePath = fileName;
    }

private string Mission_ToXml()
    {
        XmlDocument xDoc;
        XmlElement root;
        XmlAttribute xAtt;

        xDoc = new XmlDocument();

        foreach (string item in _MissionCommentsBefore)
            xDoc.AppendChild(xDoc.CreateComment(item));

        root = xDoc.CreateElement("mission_data");
        xAtt = xDoc.CreateAttribute("version");
        xAtt.Value = "1.61";
        root.Attributes.Append(xAtt); 
        xDoc.AppendChild(root);

        //Out the xml's!
        foreach (TreeNode node in _FM_tve_Mission.Nodes)
            Mission_ToXml_private_RecursivelyOut(root, xDoc, node);

        foreach (string item in _MissionCommentsAfter)
            xDoc.AppendChild(xDoc.CreateComment(item));


        //Make this look good
        StringBuilder sb = new StringBuilder();
        XmlWriterSettings settings = new XmlWriterSettings();

        settings.Indent = true;
        settings.IndentChars = "  ";
        settings.NewLineChars = "\r\n";
        settings.NewLineHandling = NewLineHandling.Replace;
        settings.OmitXmlDeclaration = true;
        using (XmlWriter writer = XmlWriter.Create(sb, settings))
        {
            xDoc.Save(writer);
        }

        return sb.ToString();
    }

private void Mission_ToXml_private_RecursivelyOut(XmlNode root, XmlDocument xDoc, TreeNode tNode)
    {
        root.AppendChild(((MissionNode)tNode.Tag).ToXml(xDoc));
        foreach (TreeNode node in tNode.Nodes)
            Mission_ToXml_private_RecursivelyOut(root, xDoc, node);
    }

这里的_FM_tve_Mission是一个TreeView控件,它有节点,每个节点都有一个MissionNode类的标签,它有ToXml方法返回包含这个MissionNode转换为xml的XmlNode

【问题讨论】:

标签: c# xml xmlwriter


【解决方案1】:

您不需要任何特殊设置:

XmlWriter output = XmlWriter.Create(filepath);
 output.writeStartElement("element");
 output.writeAttributeString("a", "1");
 output.writeEndElement();

这将为您提供&lt;element a="1" /&gt; 的输出(刚刚在我正在为其编写 xml 的应用程序中对其进行了测试)

基本上,如果您在编写结束元素之前不添加任何数据,它只会为您关闭它。

我还有以下XmlWriterSettings,如果它默认不工作,它可能是其中之一:

XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = true;
wSettings.ConformanceLevel = ConformanceLevel.Fragment;
wSettings.OmitXmlDeclaration = true;
XmlWriter output = XmlWriter.Create(filePathXml, wSettings);

【讨论】:

  • 不不不,你不明白。我有非常复杂的 XML,实际上它是一个游戏的任务编辑器,它以 xml 格式存储场景(一组脚本和事件和东西),所以它是动态生成的,我想使用 xmlwriter 来通过只做 XmlWriter 来输出它。写(myXml)
  • XmlWriter 只有一个静态的Create 方法。你不能打电话给XmlWriter.Write(),因为它不存在。您必须分别使用名称和属性编写每个节点。从你给出的解释来看,这正是你想要的。您不能只是神奇地将数据传递给 xmlwriter 并期望输出。你必须告诉它要输出什么元素和属性。
  • 啊抱歉我错了,它叫做 Save not Write.... 我的意思是使用 XmlDocument 类型的对象的方法 Save(传递 XmlWriter 对象),我在 OP 中添加了代码
  • 好吧,我的下一个问题是,您为什么要尝试像使用 XmlWriter 一样使用 XmlDocument 而不是仅使用 XmlWriter 来创建文档?您可以使用 XmlWriter 编写所有这些代码,而无需在代码中执行所有这些附加和创建元素和属性对象的操作。获得自闭合标签的唯一方法是使用 XmlWriter。将元素添加到 XmlDocument 将始终将它们作为完整元素添加(就像它们被创建一样)
  • 我发现了问题所在。我用“”分配了 XmlNode 的 InnerText。这个动作显然使它“扩展”成 > 形式。如果不分配它,它仍然是相同的“”,但它不会在没有孩子的情况下扩展。问题解决了
【解决方案2】:

处理来自外部文件的 XML,我编写了以下类来摆脱非空封闭元素。我的 XML 现在有自结束标签了。

using System.Linq;
using System.Xml.Linq;

namespace XmlBeautifier
{
    public class XmlBeautifier
    {
        public static string BeautifyXml(string outerXml)
        {
            var _elementOriginalXml = XElement.Parse(outerXml);
            var _beautifiedXml = CloneElement(_elementOriginalXml);
            return _beautifiedXml.ToString();
        }

        public static XElement CloneElement(XElement element)
        {
            // http://blogs.msdn.com/b/ericwhite/archive/2009/07/08/empty-elements-and-self-closing-tags.aspx
            return new XElement(element.Name,
                element.Attributes(),
                element.Nodes().Select(n =>
                {
                    XElement e = n as XElement;
                    if (e != null)
                        return CloneElement(e);
                    return n;
                })
            );
        }

    }
}

【讨论】:

  • XmlNode.Clone(deep_or_shallow) 没有相同的效果.. 手动删除文本元素可能会。
【解决方案3】:

使用正则表达式和递归方法,这很容易:

    using System.Xml.Linq;
    public static class Xml
    {
        /// <summary>
        /// Recursive method to shorten all xml end tags starting from a given element, and running through all sub elements 
        /// </summary>
        /// <param name="elem">Starting point element</param>
        public static void ToShortEndTags(this XElement elem)
        {
            if (elem == null) return;

            if (elem.HasElements)
            {
                foreach (var item in elem.Elements()) ToShortEndTags(item);
                return;
            }

            var reduced = Regex.Replace(elem.ToString(), ">[\\s\\n\\r]*</\\w+>", "/>");

            elem.ReplaceWith(XElement.Parse(reduced));
        }
    }

要使用它,请输入如下内容:

    var path = @"C:\SomeFile.xml";
    var xdoc = XDocument.Load(path).Root.ToShortEndTags();

xdoc 现在是从给定路径加载的XDocument 实例,但其所有符合条件的(无内容)完整结束标记现在缩短

【讨论】:

    猜你喜欢
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多