使用自定义格式创建XML文件

时间:2018-03-28 00:23:54

标签: c# xml

我需要在Attributes和几个标签上创建一个带有换行符和标签的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 >

不确定我错过了什么。

1 个答案:

答案 0 :(得分:0)

您应该看一下这个问题:xdocument save preserve white space inside tags

LoadOptions.PreserveWhitespaceLoadOptions Enum

  

如果在装载时保留空白区域,则所有无效的白色   XML树中的空间按原样在XML树中实现。如果你这样做   不保留白色空间,那么所有微不足道的白色空间都是   丢弃。

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

如果你看XElement.Parse Method,你会看到:

  

如果源XML缩进,请在其中设置PreserveWhitespace标志   选项使读者读取源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);
            }
        }
    }