Лучший .net метод для создания документа XML - PullRequest
15 голосов
/ 16 января 2010

Я пытаюсь выяснить, как лучше всего написать 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>

Ответы [ 11 ]

27 голосов
/ 16 января 2010

Ответ Джоша показывает, как легко создать отдельный элемент в LINQ to XML ... он не показывает, как легко создать несколько элементов. Предположим, у вас есть List<Order> с именем orders ... вы можете создать весь документ следующим образом:

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, с которым я работал ... он также отлично подходит для запросов.

9 голосов
/ 16 января 2010

Я бы предложил использовать классы в System.Xml.Linq.dll , которые содержат API-интерфейс XML DOM, который позволяет легко создавать XML-структуры благодаря способу проектирования конструкторов. Попытка создать структуру XML с использованием классов System.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")
    )
);
4 голосов
/ 16 января 2010

Как насчет этого: создать класс "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.

2 голосов
/ 16 января 2010

Если ваш вариант использования прост, ничто не может быть проще и проще в использовании, чем 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();
1 голос
/ 29 октября 2017

Существует новый язык под названием 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>
0 голосов
/ 01 августа 2017

Я обнаружил, что во многом это зависит от того, насколько сложны ваши исходные данные.

Если ваши данные хорошо организованы в объекты и достаточно вывести их в XML, Linq очень многословен и мощен. Но как только существуют взаимозависимости объектов, я не думаю, что вы захотите использовать однострочник Linq, так как отлаживать и / или расширять его очень сложно.

В этих случаях я бы предпочел пойти с XmlDocument, создать метод справки, чтобы облегчить добавление атрибутов к элементу (см. Ниже), и использовать Linq в циклах foreach вокруг блоков создания XML.

private void XAttr(ref XmlNode xn, string nodeName, string nodeValue)
{
    XmlAttribute result = xn.OwnerDocument.CreateAttribute(nodeName); 
    result.InnerText = nodeValue;
    xn.Attributes.Append(result);
}
0 голосов
/ 19 января 2010

В этой теме есть много хороших предложений, но один из них не был упомянут: определение ADO DataSet и сериализация / десериализация с использованием методов ReadXml и WriteXml. Это может быть очень простым и привлекательным решением. Ваш XML не в правильном формате, но он близок.

0 голосов
/ 16 января 2010

Если вы не хотите (или не можете) использовать 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);
}
0 голосов
/ 16 января 2010
// 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);
0 голосов
/ 16 января 2010

Вы просто щелкаете правой кнопкой мыши по окну вашего кода, выбираете InsertSnippet перейдите по этой ссылке

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

очень легко

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...