Как манипулировать документом XML по одному родительскому элементу за раз? - PullRequest
1 голос
/ 12 января 2012

Я пытаюсь взять файл XML, содержащий несколько заказов, из онлайн-корзины, проанализировать его и вывести значения каждого заказа в виде собственного текстового файла (не XML) с использованием C # и Visual Studio 2008.методов на данный момент, но не повезло.Моя последняя попытка включала оператор foreach, связанный с XMLNodeList, и пытался выполнить мой перевод для каждого узла с именем «Порядок», используя XMLReader для записи значения каждого элемента в строку.Кажется, что foreach не работает с текущей конфигурацией.

Есть ли лучший способ сделать это или мне нужно продолжать использовать foreach?Все мысли очень ценятся.

 class Class1
  {
     public static void Main()
      {

        StringBuilder orderid = new StringBuilder();
        StringBuilder ordernumber = new StringBuilder();
        StringBuilder name = new StringBuilder();
        StringBuilder staddress = new StringBuilder();
        StringBuilder city = new StringBuilder();
        StringBuilder state = new StringBuilder();
        StringBuilder zip = new StringBuilder();
        StringBuilder country = new StringBuilder();
        StringBuilder email = new StringBuilder();
        StringBuilder partnumber = new StringBuilder();
        StringBuilder quantity = new StringBuilder();

            XmlDocument doc = new XmlDocument();
            doc.Load(@"C:\onlinesales\neworders.xml");
            XmlNode root = doc.DocumentElement;

            XmlNodeList nodeList = root.SelectNodes("Order");
            foreach (XmlNode order in nodeList)
            {

                using (XmlReader reader = XmlReader.Create("Order"))
                {
                    reader.ReadToFollowing("OrderNumber");
                    ordernumber.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("OrderGUID");
                    orderid.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("FirstName");
                    name.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("Email");
                    email.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("BillingAddress1");
                    staddress.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("BillingCity");
                    city.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("BillingState");
                    state.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("BillingZip");
                    zip.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("BillingCountry");
                    country.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("Quantity");
                    quantity.Append(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("OrderedProductManufacturerPartNumber");
                    partnumber.Append(reader.ReadElementContentAsString());
                }

            using (StreamWriter fileout =
                new StreamWriter("W:" + DateTime.Now.ToString("yyyyy-MM-dd_hh-mm-ss-ff") + ".txt", false, Encoding.ASCII))
            {
                fileout.WriteLine("ISA*00*          *00*          *ZZ*daisywebstore  *12*5016361200     *" + DateTime.Now.ToString("yyMMdd") + "*1559*U*00400*000001649*0*P>~");
                fileout.WriteLine("GS*PO*daisywebstore*5016361200*" + DateTime.Now.ToString("yyyyMMdd") + "*" + DateTime.Now.ToString("HHmm") + "*1649*X*004010~");
                fileout.WriteLine("ST*850*13~");
                fileout.WriteLine("BEG*00*SA*08272226001*" + DateTime.Now.ToString("yyyyMMdd") + "~");
                fileout.WriteLine("REF*DP*089~");
                fileout.WriteLine("DTM*002*20120104~");
                fileout.WriteLine("N1*ST*" + name + "~");
                fileout.WriteLine("N3*" + staddress + "~");
                fileout.WriteLine("N4*" + city + "*" + state + "*" + zip + "~");
                fileout.WriteLine("N1*RE**92*00103653341~");
                fileout.WriteLine("PO1*1*6*EA*33.28*TE*IN*985880-542~");
                fileout.WriteLine("PID*F*****CO2 BB PISTOL     $ 5693~");
                fileout.WriteLine("PO4*3*1*EA~");
                fileout.WriteLine("CT*1~");
                fileout.WriteLine("AMT*1*199.68~");
                fileout.WriteLine("SE*16*13~");
            }
                    }
                //File.Delete(@"C:\onlinesales\neworders.xml");
}
}

}

Ответы [ 2 ]

3 голосов
/ 12 января 2012

Вы можете сделать это очень просто. Объектно-ориентированное программирование - это путь.

Допустим, вы создали класс Order, который принимает XElement. Я напишу пару строк для вас.

public class Order
{
    XElement self;
    public Order(XElement order)
    {
        self = order;
    }

    public XElement Element { get { return self; } }

    public string OrderNumber 
    { 
        // if your xml looks like <Order OrderNumber="somenumber" />
        get { return (string)(self.Attribute("OrderNumber") ?? (object)"some default value/null"); } 
        // but if it looks like: <Order><OrderNumber>somenumber</OrderNumber></Order>
        // get { return (string)(self.Element("OrderNumber") ?? (object)"some default value/null"); }
    }
}

Остальные свойства Ордена вы должны будете заполнить самостоятельно. Для каждого значения Order создайте свойство, подобное OrderNumber, которое я сделал выше. Наличие свойств для каждого значения заказа упрощает доступ к данным.

Итак, для вашего основного кода вы должны иметь:

XElement file = XElement.Load(@"C:\onlinesales\neworders.xml");
Order[] orders = file.Elements("Order").Select(e => new Order(e)).ToArray();

Теперь, когда у вас есть все ваши заказы как отдельные объекты Order, считывайте данные из списка свойств при выводе в файл. Теперь нет необходимости хранить значения в StringBuilder, поскольку они находятся в объектах Order.

foreach(Order order in orders)
{
   // write order.OrderNumber  etc. / do whatever you want with the orders.
}
0 голосов
/ 12 января 2012

У Чака хороший подход. Иногда вы не хотите сохранять ссылку на базовую структуру данных XML в загружаемом объекте модели. В этом случае я часто использую такой шаблон:

public interface IXmlReadable
{
    void Clear();
    void Read(XPathNavigator xmlNav);
}

public class ModelBase : IXmlReadable
{
    public void Clear()
    {
        DoClear();
    }

    public void Read(XPathNavigator xmlNav)
    {
        DoRead(xmlNav);
    }


    protected virtual void DoClear()
    {
        throw new NotImplementedException();
    }

    protected virtual void DoRead(XPathNavigator xmlNav)
    {
        throw new NotImplementedException();
    }
}

Чтение может быть перегружено для принятия XmlDocument, XmlNode, XElement и т. Д.

Теперь вы можете реализовывать конкретные модели.

public sealed class Order : ModelBase
{
    public Order() { }

    public string OrderNumber { get; private set; }

    protected override void DoClear()
    {
        OrderNumber = string.Empty;
    }

    protected override void DoRead(XPathNavigator xmlNav)
    {
        DoClear();

        XPathNavigator node;

        node = xmlNav.SelectSingleNode("OrderNumber");

        if (node != null)
            OrderNumber = node.InnerXml;

        // implement other properties here
    }

}

С подходами XPathDocument и XPathNavigator вы можете сделать что-то вроде этого:

XPathDocument xml = new XPathDocument(@"C:\onlinesales\neworders.xml");

xmlNav = xml.CreateNavigator();

XPathNodeIterator iterator = xmlNav.Select("Order");

while (iterator.MoveNext())
{
    Order order = new Order();
    order.Read(iterator.Current);

    // do something with the Order - add to list or process
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...