繁体   English   中英

创建 XML 文档的最佳 .net 方法

[英]Best .net Method to create an XML Doc

我试图找出编写 XML 文档的最佳方法。 下面是一个简单的例子,说明我试图根据我从 ERP 系统中提取的数据创建什么。 我已经阅读了 XMLWriter,但我想看看是否还有其他更好的方法。 任何建议将不胜感激。

示例 XML:

<?xml version="1.0"?>
<Orders>
  <Order OrderNumber="12345">
    <ItemNumber>0123993587</ItemNumber>
    <QTY>10</QTY>
    <WareHouse>PA019</WareHouse>
  </Order>
  <Order OrderNumber="12346">
    <ItemNumber>0123993587</ItemNumber>
    <QTY>9</QTY>
    <WareHouse>PA019</WareHouse>
  </Order>
  <Order OrderNumber="12347">
    <ItemNumber>0123993587</ItemNumber>
    <QTY>8</QTY>
    <WareHouse>PA019</WareHouse>
  </Order>
</Orders>

Josh 的回答显示了在 LINQ to XML 中创建单个元素是多么容易......它没有显示创建多个元素也非常容易。 假设您有一个名为ordersList<Order> ......您可以像这样创建整个文档:

var xml = new XElement("Orders",
    orders.Select(order =>
        new XElement("Order",
            new XAttribute("OrderNumber", order.OrderNumber),
            new XElement("ItemNumber", order.ItemNumber),
            new XElement("QTY", order.Quantity),
            new XElement("Warehouse", order.Warehouse)
        )
    )
);

LINQ to XML 使构建 XML 变得异常简单。 它还支持 XML 命名空间,这也很简单。 例如,如果您希望元素位于特定的命名空间中,您只需要:

XNamespace ns = "http://your/namespace/here";
var xml = new XElement(ns + "Orders",
    orders.Select(order =>
        new XElement(ns + "Order",
... (rest of code as before)

LINQ to XML 是我使用过的最好的 XML API……它也非常适合查询。

我建议使用System.Xml.Linq.dll中的类,其中包含一个 XML DOM API,由于构造函数的设计方式,该 API 允许轻松构建 XML 结构。 尝试使用 System.Xml 类创建 XML 结构非常痛苦,因为您必须分离创建它们,然后将它们单独添加到文档中。

是 XLinq 与 System.Xml 从头开始​​创建 DOM的示例 当您看到 System.Xml 示例时,您的眼睛会流血。

这是一个关于如何使用 XLinq 构建部分文档的快速示例。

var xml = new XElement("Orders",
    new XElement("Order",
        new XAttribute("OrderNumber", 12345),
        new XElement("ItemNumber", "01234567"),
        new XElement("QTY", 10),
        new XElement("Warehouse", "PA019")
    )
);

提示虽然它有点不正统(虽然不比最近流行的一些语言屠宰更糟糕),但我有时会使用 C# 的类型别名功能来进一步减少代码:

using XE = System.Xml.Linq.XElement;
using XA = System.Xml.Linq.XAttribute;
...
var xml = new XE("Orders",
    new XE("Order",
        new XA("OrderNumber", 12345),
        new XA("ItemNumber", "01234567"),
        new XA("QTY", 10),
        new XA("Warehouse", "PA019")
    )
);

怎么样:创建一个“订单”类和一个“订单”,然后将它们序列化为 XML - 对我来说似乎比手动一点一点地创建 XML 容易得多......

既然您说要从 ERP 中提取数据,那么您可能已经有了用于“订单”等的对象和类 - 也许在您的类上放置一些 [XmlElement] 属性就足够了,您就可以开始了!

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace XmlLinqTest
{
    [Serializable]
    [XmlRoot(Namespace = "")]
    public class Orders
    {
        private List<Order> _orders = new List<Order>();

        /// <remarks/>
        [XmlElement("Order")]
        public List<Order> OrderList
        {
            get { return _orders; }
        }
    }

    /// <remarks/>
    [Serializable]
    public class Order
    {
        /// <remarks/>
        [XmlElement]
        public string ItemNumber { get; set; }

        [XmlElement]
        public int QTY { get; set; }

        /// <remarks/>
        [XmlElement]
        public string WareHouse { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public string OrderNumber { get; set; }
    }
}

在你的主应用程序中是这样的:

Orders orders = new Orders();

Order work = new Order() { ItemNumber = "0123993587", OrderNumber = "12345", QTY = 10, WareHouse = "PA019" };
orders.OrderList.Add(work);

work = new Order() { ItemNumber = "0123993587", OrderNumber = "12346", QTY = 9, WareHouse = "PA019" };
orders.OrderList.Add(work);

work = new Order() { ItemNumber = "0123993587", OrderNumber = "12347", QTY = 8, WareHouse = "PA019" };
orders.OrderList.Add(work);

XmlSerializer ser = new XmlSerializer(typeof(Orders));

using(StreamWriter wr = new StreamWriter(@"D:\testoutput.xml", false, Encoding.UTF8))
{
    ser.Serialize(wr, orders);
}

处理对象然后将它们序列化到磁盘对我来说似乎比摆弄 XDocument 和其他 API 容易得多。

如果您的用例很简单,那么没有什么比 XmlTextWriter 更简单易用的了。 也就是说,一种替代方法是使用 XmlDocument 对象来创建和附加所有节点。 但我认为,如果您从头开始创建文档而不是操作文档,那么编写和维护使用 XmlTextWriter 的代码会更容易。 使用 XmlTextWriter 应该非常简单:

        StringBuilder output = new StringBuilder();
        XmlWriter writer = XmlWriter.Create(output);
        writer.WriteProcessingInstruction("xml", "version=\"1.0\"");
        writer.WriteStartElement("Orders");
        //...start loop...
        writer.WriteStartElement("Order");
        writer.WriteAttributeString("OrderNumber", "12345");
        writer.WriteElementString("ItemNumber", "0123993587");
        writer.WriteElementString("QTY", "10");
        writer.WriteElementString("WareHouse", "PA019");
        writer.WriteEndElement();
        //...loop...
        writer.WriteEndElement();
        writer.Close();

有一种称为XCST的新语言可以编译为 C#。

<c:template name='c:initial-template' expand-text='yes'>
   <c:param name='orders' as='IEnumerable&lt;Order>'/>

   <Orders>
      <c:for-each name='order' in='orders'>
         <Order OrderNumber='{order.Number}'>
            <ItemNumber>{order.ItemNumber}</ItemNumber>
            <QTY>{order.Quantity}</QTY>
            <WareHouse>{order.WareHouse}</WareHouse>
         </Order>
      </c:for-each>
   </Orders>
</c:template>

我必须创建以下 XML 文档,其中的某些部分已参数化。

<?xml version="1.0" encoding="utf-8"?>
<wap-provisioningdoc>
  <characteristic type="BOOTSTRAP">
    <parm name="NAME" value="SYNCSETTINGS" />
  </characteristic>
  <characteristic type="APPLICATION">
    <parm name="APPID" value="w5" />
    <parm name="TO-NAPID" value="INTERNET" />
    <parm name="NAME" value="SYNCSETTINGS" />
    <parm name="ADDR" value="http://syncserver/sync" />
    <characteristic type="RESOURCE">
      <parm name="URI" value="pb" />
      <parm name="NAME" value="Contacts DB" />
      <parm name="AACCEPT" value="text/x-vcard" />
    </characteristic>
    <characteristic type="RESOURCE">
      <parm name="URI" value="cal" />
      <parm name="NAME" value="Calendar DB" />
      <parm name="AACCEPT" value="text/x-vcalendar" />
    </characteristic>
    <characteristic type="RESOURCE">
      <parm name="URI" value="notes" />
      <parm name="NAME" value="Notes DB" />
      <parm name="AACCEPT" value="text/plain" />
    </characteristic>
    <characteristic type="APPAUTH">
      <parm name="AAUTHNAME" value="username" />
      <parm name="AAUTHSECRET" value="password" />
    </characteristic>
  </characteristic>
</wap-provisioningdoc>

这是我使用单个 LINQ 语句执行此操作的代码。

请注意,上面使用 LINQ 创建 XML 文档并将其保存到 XML 文件会保留 XML 文档格式并保留换行符和回车符,从而使文档正确制表。

public string CreateOTAXmlFile(string Username, string Password)
    {
        var ota = new XDocument(
                    new XElement("wap-provisioningdoc",
                        new XElement("characteristic", new XAttribute("type", "BOOTSTRAP"),
                            new XElement("parm", new XAttribute("name", "NAME"), new XAttribute("value", "SYNCSETTINGS"))
                                    ),
                        new XElement("characteristic", new XAttribute("type", "APPLICATION"),
                            new XElement("parm", new XAttribute("name", "APPID"), new XAttribute("value", "w5")),
                            new XElement("parm", new XAttribute("name", "TO-NAPID"), new XAttribute("value", "INTERNET")),
                            new XElement("parm", new XAttribute("name", "NAME"), new XAttribute("value", "SYNCSETTINGS")),
                            new XElement("parm", new XAttribute("name", "ADDR"), new XAttribute("value", "http://syncserver/sync")),
                            new XElement("characteristic", new XAttribute("type", "RESOURCE"),
                                new XElement("parm", new XAttribute("name", "URI"), new XAttribute("value", "pb")),
                                new XElement("parm", new XAttribute("name", "NAME"), new XAttribute("value", "Contacts DB")),
                                new XElement("parm", new XAttribute("name", "AACCEPT"), new XAttribute("value", "text/x-vcard"))
                                        ),
                            new XElement("characteristic", new XAttribute("type", "RESOURCE"),
                                new XElement("parm", new XAttribute("name", "URI"), new XAttribute("value", "cal")),
                                new XElement("parm", new XAttribute("name", "NAME"), new XAttribute("value", "Calendar DB")),
                                new XElement("parm", new XAttribute("name", "AACCEPT"), new XAttribute("value", "text/x-vcalendar"))
                                        ),
                            new XElement("characteristic", new XAttribute("type", "RESOURCE"),
                                new XElement("parm", new XAttribute("name", "URI"), new XAttribute("value", "notes")),
                                new XElement("parm", new XAttribute("name", "NAME"), new XAttribute("value", "Notes DB")),
                                new XElement("parm", new XAttribute("name", "AACCEPT"), new XAttribute("value", "text/plain"))
                                        ),
                            new XElement("characteristic", new XAttribute("type", "APPAUTH"),
                                new XElement("parm", new XAttribute("name", "AAUTHNAME"), new XAttribute("value", Username)),
                                new XElement("parm", new XAttribute("name", "AAUTHSECRET"), new XAttribute("value", Password))
                                        )
                                    )
                                )
                            );

        ota.Save(Server.MapPath("~/OTA/") + Username + ".xml");
        return (ota.ToString());

    }
// Create the xml document containe
XmlDocument doc = new XmlDocument();// Create the XML Declaration, and append it to XML document
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", null, null);
doc.AppendChild(dec);// Create the root element
XmlElement root = doc.CreateElement("Library");
doc.AppendChild(root);
// Create Books
// Note that to set the text inside the element,
// you use .InnerText instead of .Value (which will throw an exception).
// You use SetAttribute to set attribute
XmlElement book = doc.CreateElement("Book");
book.SetAttribute("BookType", "Hardcover");
XmlElement title = doc.CreateElement("Title");
title.InnerText = "Door Number Three";
XmlElement author = doc.CreateElement("Author");
author.InnerText = "O'Leary, Patrick";
book.AppendChild(title);
book.AppendChild(author);
root.AppendChild(book);
book = doc.CreateElement("Book");
book.SetAttribute("BookType", "Paperback");
title = doc.CreateElement("Title");
title.InnerText = "Lord of Light";
author = doc.CreateElement("Author");
author.InnerText = "Zelanzy, Roger";
book.AppendChild(title);
book.AppendChild(author);
root.AppendChild(book);
string xmlOutput = doc.OuterXml;
The same code but using an XMLWriter to a memory stream.

XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = true;
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms, wSettings);// Write Declaration
xw.WriteStartDocument();
// Write the root node
xw.WriteStartElement("Library");
// Write the books and the book elements
xw.WriteStartElement("Book");
xw.WriteStartAttribute("BookType");
xw.WriteString("Hardback");
xw.WriteEndAttribute();
xw.WriteStartElement("Title");
xw.WriteString("Door Number Three");
xw.WriteEndElement();
xw.WriteStartElement("Author");
xw.WriteString("O'Leary, Patrick");
xw.WriteEndElement();
xw.WriteEndElement();
// Write another book
xw.WriteStartElement("Book");
xw.WriteStartAttribute("BookType");
xw.WriteString("Paperback");
xw.WriteEndAttribute();
xw.WriteStartElement("Title");
xw.WriteString("Lord of Light");
xw.WriteEndElement();
xw.WriteStartElement("Author");
xw.WriteString("Zelanzy, Roger");
xw.WriteEndElement();
xw.WriteEndElement();
// Close the document
xw.WriteEndDocument();
// Flush the write
xw.Flush();
Byte[] buffer = new Byte[ms.Length];
buffer = ms.ToArray();
string xmlOutput = System.Text.Encoding.UTF8.GetString(buffer);

如果您不想(或不能)使用LINQ to XML ,也不复制您的Order类以包含 XML 序列化,并且认为XmlWriter过于冗长,您可以使用普通的经典XmlDocument类:

// consider Order class that data structure you receive from your ERP system
List<Order> orders = YourERP.GetOrders();
XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("Orders"));
foreach (Order order in orders)
{
    XmlElement item = xml.CreateElement("Order");
    item.SetAttribute("OrderNumber", order.OrderNumber);
    item.AppendChild(xml.CreateElement("ItemNumber")).Value = order.ItemNumber;
    item.AppendChild(xml.CreateElement("QTY"       )).Value = order.Quantity;
    item.AppendChild(xml.CreateElement("WareHouse" )).Value = order.WareHouse;
    xml.DocumentElement.AppendChild(item);
}

有很多好的建议在此线程,但是一个尚未提及:定义一个ADO DataSet和序列化/使用反序列化ReadXmlWriteXml方法。 这可能是一个非常简单且有吸引力的解决方案。 您的 XML 的格式不太正确,但很接近。

我发现这在很大程度上取决于原始数据的复杂程度。

如果您的数据在对象中被很好地组织起来并且以 XML 格式转储它就足够了,Linq 是非常详细和强大的。 但是一旦存在对象相互依赖关系,我认为您不想使用 Linq one-liner,因为调试和/或扩展真的很痛苦。

对于这些情况,我更喜欢使用 XmlDocument,创建一个帮助方法来促进向元素添加属性(见下文),并在围绕 XML 创建块的 foreach 循环中使用 Linq。

private void XAttr(ref XmlNode xn, string nodeName, string nodeValue)
{
    XmlAttribute result = xn.OwnerDocument.CreateAttribute(nodeName); 
    result.InnerText = nodeValue;
    xn.Attributes.Append(result);
}

您只需右键单击您的代码窗口,选择 InsertSnippet 按照此链接

 Data-Xml.....>Xml>Xmlcreate

这很容易

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM