【问题标题】:Best .net Method to create an XML Doc创建 XML 文档的最佳 .net 方法
【发布时间】:2010-01-16 06:36:07
【问题描述】:

我正在尝试找出编写 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>

【问题讨论】:

  • 它在源代码中。我试图将帖子编辑为对 XML 进行 HTML 编码,但它也不起作用。老实说,即使我几乎每天都使用这个网站,但我不知道如何发布 XML!
  • 您的商品编号真的需要补零吗?

标签: c# .net xml


【解决方案1】:

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

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……它也非常适合查询。

【讨论】:

  • 谢谢乔恩。我正在使用.Net 3.5,所以这应该可以完美运行。正如您所看到的,当谈到 XML 时,我仍然是新手/无知,所以我试图更好地理解基础知识以及最适合的方法。我很欣赏所有的建议,并且一定会尝试一下。谢谢!
  • 这正是我想要的......我将从我们的数据库构建一个订单对象,然后想用它来构建 XML。应该可以完美运行。
  • 第一个例子中的小错误,倒数第二行不应该有分号。为了对上面的帖子进行编辑的小修复,所以这里有一个评论。另外,我会将每个尾括号放在每一行,正确缩进:-)
【解决方案2】:

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

Here's an example 的 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")
    )
);

【讨论】:

  • 只要目标是 .NET 3.5 或 4.0,这是一个非常好的建议。
  • 如果项目编号确实需要补零,则必须将其指定为字符串而不是数字。我希望情况并非如此。
  • ItemNumber 实际上是一个 UPC,所以它们通常是零填充的。在内部,每个人都将其称为 ItemNumber,因为这是我们 ERP 系统中的字段,并且填充了 UPC。我会试试你的建议谢谢大家。
【解决方案3】:

这个怎么样:创建一个类“Order”和一个“Orders”,然后将它们序列化为 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 容易得多。

【讨论】:

    【解决方案4】:

    如果您的用例很简单,那么没有什么比 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();
    

    【讨论】:

    • 我会说 LINQ to XML 比 XmlTextWriter 简单得多。
    • 请注意,没有任何构造函数采用 TextWriter 和编码...您需要提供文件名或 Stream... 或 just 提供TextWriter,但使用发布了 UTF-8 编码的文本。
    • -1:你需要在StringWriter 周围加上一个using 块,而XmlTextWriter 已被弃用,取而代之的是XmlWriter.Create
    • 乔恩 - 你是对的,我的错。约翰 - 在技术上不推荐使用,但一个很好的建议。我已经更新了代码。
    【解决方案5】:

    有一种名为 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>
    

    【讨论】:

      【解决方案6】:

      我必须创建以下 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());
      
          }
      

      【讨论】:

        【解决方案7】:
        // 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 解决方案。
        【解决方案8】:

        如果您不想(或不能)使用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);
        }
        

        【讨论】:

          【解决方案9】:

          在这个线程中有很多好的建议,但没有提到一个:定义 ADO DataSet 并使用 ReadXmlWriteXml 方法进行序列化/反序列化。这可能是一个非常简单且有吸引力的解决方案。您的 XML 格式不完全正确,但很接近。

          【讨论】:

            【解决方案10】:

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

            如果您的数据在对象中组织得很好,并且以 XML 形式转储就足够了,那么 Linq 非常冗长且功能强大。但是,一旦存在对象相互依赖关系,我认为您不想使用 Linq 单线,因为调试和/或扩展确实很痛苦。

            对于这些情况,我更喜欢使用 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);
            }
            

            【讨论】:

              【解决方案11】:

              您只需右键单击您的代码窗口,选择 InsertSnippet 关注这个链接

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

              很简单

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-11-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-12-22
                • 2014-03-28
                • 1970-01-01
                相关资源
                最近更新 更多