【问题标题】:Create XML file with custom formatting创建具有自定义格式的 XML 文件
【发布时间】:2018-03-28 00:23:53
【问题描述】:

我需要创建一个 XML 文件,其中包含属性中的换行符和制表符以及一些标签。所以我尝试如下。

string xmlID = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<PersonLib Version=\"1.0\"></PersonLib>";
XDocument doc = XDocument.Parse(xmlID);//, LoadOptions.PreserveWhitespace);
XElement device = doc.Root;
using (StringWriter str = new StringWriter())
using (XmlTextWriter xml = new XmlTextWriter(str))
{
    xml.Formatting=Formatting.Indented;

    xml.WriteStartElement("Details");
    xml.WriteWhitespace("\n\t");
    xml.WriteStartElement("Name");
    xml.WriteWhitespace("\n\t\t");
    xml.WriteStartElement("JohnDoe");
    xml.WriteAttributeString("DOB", "10");
    xml.WriteAttributeString("FirstName", "20");
    xml.WriteAttributeString("LastName", "40");
    xml.WriteAttributeString("\n\t\t\tAddress", "50");
    xml.WriteAttributeString("\n\t\t\tPhoneNum", "60");
    xml.WriteAttributeString("\n\t\t\tCity", "70");
    xml.WriteAttributeString("\n\t\t\tState", "80");
    xml.WriteAttributeString("\n\t\t\tCountry", "90");
    //xml.WriteWhitespace("\n\t\t");
    xml.WriteEndElement();
    xml.WriteWhitespace("\n\t");
    xml.WriteEndElement();
    xml.WriteWhitespace("\n");
    xml.WriteEndElement();
    Console.WriteLine(str);

    device.Add(XElement.Parse(str.ToString(), LoadOptions.PreserveWhitespace));

    File.WriteAllText("MyXML.xml", device.ToString());

我可以生成所需格式的 XML,但在这种情况下,当我尝试将其添加到父 XMLElement device 时,问题就出现了。尽管LoadOptions.PreserveWhitespace,格式已经全部消失。

我明白了

<PersonLib Version="1.0">
  <Details>
    <Name>
        <JohnDoe DOB="10" FirstName="20" LastName="40" Address="50" PhoneNum="60" City="70" State="80" Country"90" />
    </Name>
</Details>
</PersonLib >

当我需要的时候

<PersonLib Version="1.0">
    <Details>
        <Name>
            <JohnDoe DOB="10" FirstName="20" LastName="40"
                        Address="50"
                        PhoneNum="60"
                        City="70"
                        State="80"
                        Country="90" />
        </Name>
    </Details>
</PersonLib >

不知道我错过了什么。

【问题讨论】:

  • 哦,这是一个糟糕的例子。我的元素名称中没有空格..我只是更正了它
  • 如果你只是想让你的 xml 在新的一行中使用属性格式化,你可以看看这个问题:stackoverflow.com/questions/8237165/…
  • 我想问你为什么觉得需要这样的输出。它只不过是一种在属性之间没有格式的 XML。您是否正在使用非 XML 进程来尝试解释它?
  • 这个 xml 文件被输入到只接受上述格式的系统中。它是第三方工具,客户对该工具的输入格式非常严格。所以我们应该在 xml 中有这样的格式,以便用户使用这个 xmll
  • @Dweeberly 正如您在我的目标输出 XML 格式中看到的那样,并非所有属性都在新行中,我只希望它们中的一些在新行中,我可以像在代码中那样控制它们。但我的问题是,一旦我使用 XElement.Parse 方法,所有格式都会丢失。

标签: c# xml


【解决方案1】:

你应该看看这个问题:xdocument save preserve white space inside tags

LoadOptions.PreserveWhitespace (LoadOptions Enum)

如果您在加载时保留空白,则所有无关紧要的白色 XML 树中的空间按原样在 XML 树中具体化。如果你这样做 不保留空白,那么所有无关紧要的空白都是 丢弃。

这给人的印象是属性之间的“无关紧要”的空白将被保留。

如果您查看XElement.Parse Method,您会看到:

如果源 XML 是缩进的,则在 options 使阅读器读取源 XML 中的所有空白。 XText 类型的节点是为重要和不重要的节点创建的 空白。

查看类层次结构,您可以看到 XAttribute 不是从 XNode 继承的。属性之间的长短不一的空格不会被保留。如果是这样,您仍然必须禁用输出格式(例如ToString(SaveOptions.DisableFormatting))。

我不认为属性被设计为像你一样使用,但它是一种非常常见的用法。对此有相当多的意见(见:Attribute vs Element

无论哪种方式,听起来您都被所提供的设计和格式所困扰。不幸的是,这意味着您还必须创建自定义格式化程序才能获得所需的输出。

请注意,以下代码仅作为示例一种可能的方式来实现创建您询问的格式的代码。

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

namespace FormatXml {
    class Program {
        static String OutputElement(int indentCnt, XElement ele) {
            StringBuilder sb = new StringBuilder();

            var indent = "".PadLeft(indentCnt, '\t');
            var specialFormat = (ele.Parent == null) ? false : ((ele.Parent.Name == "Name") ? true : false);
            sb.Append($"{indent}<{ele.Name}");

            String FormatAttr(XAttribute attr) {
                return $"{attr.Name} = '{attr.Value}'";
                }

            String FormatAttrByName(String name) {
                var attr = ele.Attributes().Where(x => x.Name == name).FirstOrDefault();
                var rv = "";
                if (attr == null) {
                    rv = $"{name}=''";
                    }
                else {
                    rv = FormatAttr(attr);
                    }
                return rv;
                }

            if (specialFormat) {
                var dob       = FormatAttrByName("DOB");
                var firstName = FormatAttrByName("FirstName");
                var lastName  = FormatAttrByName("LastName");
                var address   = FormatAttrByName("Address");
                var phoneNum  = FormatAttrByName("PhoneNum");
                var city      = FormatAttrByName("City");
                var state     = FormatAttrByName("State");
                var country   = FormatAttrByName("Country");
                sb.AppendLine($"{dob} {firstName} {lastName}");
                var left = ele.Name.LocalName.Length + 5;
                var fill = indent + "".PadLeft(left);
                sb.AppendLine($"{fill}{address}");
                sb.AppendLine($"{fill}{phoneNum}");
                sb.AppendLine($"{fill}{city}");
                sb.AppendLine($"{fill}{state}");
                sb.AppendLine($"{fill}{country} />");
                }
            else {
                foreach (var attr in ele.Attributes()) {
                    sb.AppendFormat(" {0}", FormatAttr(attr));
                    }
                }
            sb.AppendLine(">");

            foreach (var e in ele.Elements()) {
                sb.Append(OutputElement(indentCnt + 1, e));
                }
            sb.AppendLine($"{indent}</{ele.Name}>");
            return sb.ToString();
            }

        static void Main(string[] args) {
            var txtEle = @"
    <Details>
        <Name>
            <JohnDoe DOB = '10' FirstName = '20' LastName = '40'
                         Address = '50'
                         PhoneNum = '60'
                         City = '70'
                         State = '80'
                         Country = '90' />
        </Name>
    </Details>";

            var plib = new XElement("PersonLib");
            XDocument xdoc = new XDocument(plib);
            var nameEle = XElement.Parse(txtEle, LoadOptions.PreserveWhitespace);
            xdoc.Root.Add(nameEle);

            var xml = OutputElement(0, (XElement)xdoc.Root);

            Console.WriteLine(xml);
            }
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-23
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 2014-02-17
    • 2021-10-06
    • 1970-01-01
    相关资源
    最近更新 更多