разбить xml-документ на части

У меня есть большой XML-документ, который нужно обрабатывать по 100 записей за раз.

Это делается в службе Windows, написанной на С#.

Структура следующая:

<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» и иметь одно и то же пространство имен и т. д.

Это возможно?


person ChrisCa    schedule 30.10.2008    source источник


Ответы (3)


Еще одно наивное решение; на этот раз для .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;
    }
person Jim Burger    schedule 30.10.2008

Наивный, итеративный, но работает [EDIT: только в .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;
    }
person Jim Burger    schedule 30.10.2008
comment
Я знаю, что это ужасно неэффективно. - person Jim Burger; 30.10.2008

Если причина обработки 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
  }     
}
person Ray Lu    schedule 30.10.2008