1

私は 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());

        //...

}

「注文」タグでネストされたタグを読み取るのに問題があります。また、要素/タグの「追加」には「追加」の番号が付いている場合があります。タグ/要素の場合もあれば、そうでない場合もあります。

この xml が生成されるコードにアクセスできないため、このパターンを読む必要があります。

これまでグループ化を試みましたが、第 2 および第 3 レベルの要素を操作できません。

読んだ後、これらの値をデータベースに保存します。

ありがとう、

4

5 に答える 5

1

何か問題がある場合はお知らせください。これをテストする機会がありませんでした。また、複製される要素のいくつかを想定する必要がありました

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()
            }
};
于 2013-07-19T18:40:23.690 に答える
1

ネストされた要素については、次のように続け.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;
}

(もちろん、より多くのエラー処理が必要ですが、アイデアは得られます。)

于 2013-07-19T18:26:57.047 に答える
0

クエリで 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"),
                    },
            },
    };
于 2013-07-19T18:51:47.730 に答える
0

動作テスト済み。これは、いくつかの追加のクラスを定義せずに一発で行うことは不可能です。ここでは、ピボット インターフェイスと、インターフェイスとItemを実装する 2 つのクラスがあります。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);
    }
}
于 2013-07-19T18:45:19.193 に答える