Лучший метод .net для создания XML-документа
Я пытаюсь выяснить, какой лучший метод для написания 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>
Ответы
Ответ 1
Ответ Josh показывает, как легко создать один элемент в 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-интерфейс, с которым я работал... он отлично подходит для запросов.
Ответ 2
Я бы предложил использовать классы в System.Xml.Linq.dll, которые содержат XML DOM API, который позволяет легко наращивать Структуры XML из-за того, как проектировщики разрабатываются. Попытка создать структуру XML с использованием классов System.Xml очень болезненна, потому что вы должны создать их отдельно, а затем отдельно добавить их в документ.
Вот пример XLinq vs. 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")
)
);
СОВЕТ Хотя это немного неортодоксально (хотя и не хуже, чем некоторые из рангов, которые стали популярными в последнее время), я иногда использовал функцию сглаживания типа С#, чтобы еще больше уменьшить код:/p >
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")
)
);
Ответ 3
Как насчет этого: создайте класс "Заказ" и один "Заказы", а затем сериализуйте их в XML - мне намного легче, чем создавать бит XML из бит... [/p >
Поскольку вы говорите, что вы извлекаете данные из своего ERP, у вас, вероятно, уже есть объекты и классы для "Order" и т.д. - может быть, достаточно разместить несколько атрибутов [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();
Ответ 5
Мне пришлось создать следующий 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.
Обратите внимание на то, что создание XML-документа выше с использованием LINQ и сохранение его в файле 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());
}
Ответ 6
// 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);
Ответ 7
Если вы не хотите (или не можете) использовать 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);
}
Ответ 8
В этом потоке есть много хороших предложений, но не упомянутых: определение ADO DataSet
и сериализация/десериализация с использованием методов ReadXml
и WriteXml
. Это может быть очень простым и привлекательным решением. Ваш XML не в правильном формате, но он близок.
Ответ 9
Я нашел, что это во многом зависит от того, насколько сложны ваши исходные данные.
Если ваши данные хорошо организованы в объекты, и их достаточно, чтобы выгрузить их в 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);
}
Ответ 10
Появился новый язык под названием XCST, который компилируется на С#.
<c:template name='c:initial-template' expand-text='yes'>
<c:param name='orders' as='IEnumerable<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>
Ответ 11
Вы просто щелкните правой кнопкой мыши на своем окне кода, выберите InsertSnippet
следуйте этой ссылке
Data-Xml.....>Xml>Xmlcreate
его очень легко