繁体   English   中英

如何使用LINQ to XML读取此XML

[英]how to read this XML using LINQ to XML

我是LINQ to XML的新手,目前使用以下XML:

<invoices>
  <invoice>
    <order_id>85</order_id>
    <time>02:52 PM</time>
    <date>24-05-2013</date>
    <order>
      <item>
        <Main>
          <id>343</id>
          <Qty>1</Qty>
        </Main>
        <Add />
      </item>
      <item>
        <Main>
          <id>3</id>
          <Qty>1</Qty>
        </Main>
        <Add>
          <Extra id="1">
            <Qty>1</Qty>
            <Desc>Regular</Desc>
          </Extra>
        </Add>
      </item>
    </order>
  </invoice>
  <invoice>
    <order_id>88</order_id>
    <time>03:10 PM</time>
    <date>24-05-2013</date>
    <order>
      <item>
        <Main>
          <id>345</id>
          <Qty>1</Qty>
        </Main>
        <Add />
      </item>
      <item>
        <Main>
          <id>2</id>
          <Qty>2</Qty>
        </Main>
        <Add>
          <Extra id="1">
            <Qty>1</Qty>
            <Desc>Regular</Desc>
          </Extra>
        </Add>
      </item>
    </order>
  </invoice>
</invoices>

到目前为止,我已经编写了以下代码:

void queryData(XDocument doc)
{
        var data = from item in doc.Descendants("invoice")
                   select new
                   {
                       orderId = item.Element("order_id").Value,
                       orderDate = item.Element("date").Value,
                       orderTime = item.Element("time").Value
                   };
        foreach(var p in data)
            Console.WriteLine(p.ToString());

        //...

}

我无法在“order”标签中阅读嵌套标签。 元素/标签“添加”有时也有“额外”号。 标签/元素,有时不是。

我无法访问生成此xml的代码,因此必须阅读此模式。

到目前为止,我已经尝试过分组,但我无法使用二级和三级元素。

阅读后,我会将这些值保存到数据库中。

谢谢,

对于嵌套元素,只需继续使用.Element("name")

orderQuantities = item.Element("order").Elements("item")
    .Select(orderItem => new { 
        id = orderItem.Element("Main").Element("id")),
        qty = orderItem.Element("Main").Element("Qty"))
     }).ToArray(),

对于您不确定存在的元素,您始终可以编写辅助方法:

extraQty = GetExtra(item),

GetExtra会是这样的:

public int GetExtra(XElement element)
{
    XElement extra = element.Element("Add").Element("Extra");
    if (extra != null) return int.Parse(extra.Element("Qty").Value);
    else return 0;
}

(当然需要更多的错误处理,但你明白了。)

让我知道,如果我有所作为,我没有机会测试这一点,并且还必须假设一些要重复的元素

var data = from item in doc.Descendants ( "invoice" )
    select new {
        orderId = item.Element ( "order_id" ).Value ,
        orderDate = item.Element ( "date" ).Value ,
        orderTime = item.Element ( "time" ).Value ,
        items = 
            from order in item.Element ( "order" ).Descendants ( "item" )
            let main = order.Element ( "Main" )
            let adds = order.Elements ( "Add" )
            select new {
                Main = new {
                    id = main.Element ( "id" ).Value ,
                    Qty = main.Element ( "Qty" ).Value
                } ,
                Add = 
                (from add in adds
                    let extras = add.Elements ( "Extra" )
                    select new {
                                Extra = ( from extra in extras
                                        select new {
                                                extraId = extra.Attribute("id").Value,
                                                Qty = extra.Element ( "Qty" ).Value ,
                                                Desc = extra.Element ( "Desc" ).Value
                                            }).FirstOrDefault ( )
                            }).FirstOrDefault()
            }
};

这是解析你的xml:

var parser = new Parser();
XDocument xdoc = XDocument.Load(path_to_xml);
var orders = from invoice in xdoc.Root.Elements()
             select parser.ParseOrderFrom(invoice);

就这样。 我创建了以下类。 订单,它包含订单商品的集合并具有很好的解析日期:

public class Order
{
    public int Id { get; set; }
    public DateTime Date { get; set; }
    public List<OrderItem> Items { get; set; }
}

订购商品,这是您的主菜。 它还有内部附加列表(如果有的话):

public class OrderItem
{
    public int Id { get; set; }
    public int Quantity { get; set; }
    public List<Extra> Extras { get; set; }
}

和额外课程:

public class Extra
{
    public int Id { get; set; }
    public int Quantity { get; set; }
    public string Description { get; set; }
}

如果需要,所有解析都在单独的解析器类中进行(这将保持域类清洁):

public class Parser
{
    public Order ParseOrderFrom(XElement invoice)
    {
        string time = (string)invoice.Element("time");
        string date = (string)invoice.Element("date");

        return new Order {
           Id = (int)invoice.Element("order_id"),
           Date = DateTime.ParseExact(date + time, "dd-MM-yyyyhh:mm tt", null),
           Items = invoice.Element("order").Elements("item")
                          .Select(i => ParseOrderItemFrom(i)).ToList()
        };
    }

    public OrderItem ParseOrderItemFrom(XElement item)
    {
        var main = item.Element("Main");

        return new OrderItem {
            Id = (int)main.Element("id"),
            Quantity = (int)main.Element("Qty"),
            Extras = item.Element("Add").Elements("Extra")
                         .Select(e => ParseExtraFrom(e)).ToList()
        };
    }

    public Extra ParseExtraFrom(XElement extra)
    {
        return new Extra {
            Id = (int)extra.Attribute("id"),
            Quantity = (int)extra.Element("Qty"),
            Description = (string)extra.Element("Desc")
        };
    }
}

测试工作。 如果不定义一些额外的类,这是不可能一次完成的。 这里我有一个pivot-interface Item ,然后是两个实现AdditemMainItem接口的类。

随意询问有关任何部分的解释。

// Since there are different types of items, we need an interface/abstact
// class to pivot.
public interface Item {
}

// The information neccesary for storing the 'Extra' element.
public class Extra {
    public Int32 ID { get; private set; }
    public Int32 Quantity { get; private set; }
    public String Description { get; private set; }

    public Extra(XElement extra) {

        // Here we load up all of the details from the 'extra' element
        this.ID = Int32.Parse(extra.Attribute("id").Value);
        this.Quantity = Int32.Parse(extra.Element("Qty").Value); ;
        this.Description = extra.Element("Desc").Value;
    }
}

// The 'add-item' is associated with the 'add' tag in the actual XML.
public class AddItem : Item {

    public IEnumerable<Extra> Extras { get; private set; }

    // The 'extras' is a collection of many items, so we require
    // an ienumerable.
    public AddItem(IEnumerable<Extra> extras) {
        this.Extras = extras;
    }

}

// The storage for the 'main-item'
public class MainItem : Item {
    public Int32 ID { get; private set; }
    public Int32 Quantity { get; private set; }

    public MainItem(Int32 id, Int32 quantity) {
        this.ID = id;
        this.Quantity = quantity;
    }
}

class Program {
    static void Main(string[] args) {
        String data = File.ReadAllText("File.txt");

        XElement tree = XElement.Parse(data);


        var projection = tree.Elements()
            .Select(invoice => new {
                // Project the main details of the invoice { OrderID, Time, Date, Order }
                // The order itself needs to be projected again though because it too is a 
                // collection of sub items.
                OrderID = invoice.Element("order_id").Value,
                Time = invoice.Element("time").Value,
                Date = invoice.Element("date").Value,
                Order = invoice.Element("order")
                    .Elements()
                    .Elements()
                    .Select(item => {

                        // First, we need to know what type of item this 'order' is.
                        String itemType = item.Name.ToString();

                        // If its a 'main' item, then return that type.
                        if (itemType == "Main") {
                            Int32 id = Int32.Parse(item.Element("id").Value);
                            Int32 quantity = Int32.Parse(item.Element("Qty").Value);

                            return (Item)new MainItem(id, quantity);
                        }

                        // If it's an 'Add' item. Then we have to:
                        if (itemType == "Add") {
                            // (1) Capture all of the extras.
                            IEnumerable<Extra> extras = item.Elements()
                                .Select(extra => new Extra(extra))
                                .ToList();

                            // (2) Add the extras to a new AddItem. Then return the 'add'-item.
                            // Notice that we have to cast to 'Item' because we are returning 
                            // a 'Main'-item sometimes and an 'add' item other times.
                            // Select requires the return type to be the same regardless.
                            return (Item)new AddItem(extras);
                        }

                        // Hopefully this path never hits.
                        throw new NotImplementedException("This path not defined");

                    }).ToList()

            }).ToList();

        Console.WriteLine(projection);
    }
}

如果在查询中使用某个xpath,则可以使事情更易于管理。 如果你问我,在这里使用纯LINQ to XML会变得太冗长。

var query =
    from invoice in doc.XPathSelectElements("/invoices/invoice")
    select new
    {
        OrderId = (int)invoice.Element("order_id"),
        Time = (string)invoice.Element("time"),
        Date = (string)invoice.Element("date"),
        Items =
            from item in invoice.XPathSelectElements("./order/item")
            select new
            {
                Id = (int)item.XPathSelectElement("./Main/id"),
                Quantity = (int)item.XPathSelectElement("./Main/Qty"),
                Extras =
                    from extra in item.XPathSelectElements("./Add/Extra")
                    select new
                    {
                        Id = (int)extra.Attribute("id"),
                        Quantity = (int)extra.Element("Qty"),
                        Description = (string)extra.Element("Desc"),
                    },
            },
    };

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM