У меня есть большой XML-документ, который нужно обрабатывать по 100 записей за раз
Это делается в рамках службы Windows, написанной на C#.
Структура следующая:
<docket xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "docket.xsd">
<order>
<Date>2008-10-13</Date>
<orderNumber>050758023</orderNumber>
<ParcelID/>
<CustomerName>sddsf</CustomerName>
<DeliveryName>dsfd</DeliveryName>
<Address1>sdf</Address1>
<Address2>sdfsdd</Address2>
<Address3>sdfdsfdf</Address3>
<Address4>dffddf</Address4>
<PostCode/>
</order>
<order>
<Date>2008-10-13</Date>
<orderNumber>050758023</orderNumber>
<ParcelID/>
<CustomerName>sddsf</CustomerName>
<DeliveryName>dsfd</DeliveryName>
<Address1>sdf</Address1>
<Address2>sdfsdd</Address2>
<Address3>sdfdsfdf</Address3>
<Address4>dffddf</Address4>
<PostCode/>
</order>
.....
.....
</docket>
В досье могут быть тысячи заказов.
Мне нужно нарезать это на 100 кусков элементов
Однако каждый из 100 заказов по-прежнему должен быть заключен в родительский узел "docket" и иметь то же пространство имен и т. д.
Это возможно?





Наивно, итеративно, но работает [Обновлено: только в .NET 3.5]
public List<XDocument> ChunkDocket(XDocument docket, int chunkSize)
{
var newDockets = new List<XDocument>();
var d = new XDocument(docket);
var orders = d.Root.Elements("order");
XDocument newDocket = null;
do
{
newDocket = new XDocument(new XElement("docket"));
var chunk = orders.Take(chunkSize);
newDocket.Root.Add(chunk);
chunk.Remove();
newDockets.Add(newDocket);
} while (orders.Any());
return newDockets;
}
Еще одно наивное решение; на этот раз для .NET 2.0. Это должно дать вам представление о том, как делать то, что вы хотите. Использует выражения Xpath вместо Linq to XML. Разбивает список заказов на 100 заказов на 10 документов менее чем за секунду на моем devbox.
public List<XmlDocument> ChunkDocket(XmlDocument docket, int chunkSize)
{
List<XmlDocument> newDockets = new List<XmlDocument>();
//
int orderCount = docket.SelectNodes("//docket/order").Count;
int chunkStart = 0;
XmlDocument newDocket = null;
XmlElement root = null;
XmlNodeList chunk = null;
while (chunkStart < orderCount)
{
newDocket = new XmlDocument();
root = newDocket.CreateElement("docket");
newDocket.AppendChild(root);
chunk = docket.SelectNodes(String.Format("//docket/order[position() > {0} and position() <= {1}]", chunkStart, chunkStart + chunkSize));
chunkStart += chunkSize;
XmlNode targetNode = null;
foreach (XmlNode c in chunk)
{
targetNode = newDocket.ImportNode(c, true);
root.AppendChild(targetNode);
}
newDockets.Add(newDocket);
}
return newDockets;
}
Если причина для обработки 100 заказов одновременно связана с производительностью, например тратя слишком много времени и ресурсов на открытие большого файла, вы можете использовать XmlReader для обработки элементов заказа по одному без снижения производительности.
XmlReader reader = XmlReader.Create(@"c:\foo\Doket.xml")
while( reader.Read())
{
if (reader.LocalName == "order")
{
// read each child element and its value from the reader.
// or you can deserialize the order element by using a XmlSerializer and Order class
}
}
Я знаю, что это ужасно неэффективно.