嵌套在c#中使用LINQ查询xml文档

时间:2015-07-15 18:37:39

标签: c# xml linq

我正在尝试使用LINQ从xml文档中检索数据到C#中的数组,我必须在xml数据的元素中使用一些嵌套查询,如下所示

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>    
    <Catalog>
     <Book ISBN="1.1.1.1" Genre="Thriller">
      <Title  Side="1">
       <Pty R="1" ID="Seller_ID">
         <Sub Typ="26" ID="John">
         </Sub>
       </Pty>
       <Pty R="2" ID="ABC">
       </Pty>
        </Title>
    </Book>
    <Book ISBN="1.2.1.1" Genre="Thriller">
      <Title  Side="2">
       <Pty R="1" ID="Buyer_ID">
         <Sub Typ="26" ID="Brook">
         </Sub>
       </Pty>
       <Pty R="2" ID="XYZ">
       </Pty>
        </Title>
    </Book>
    </Catalog>

在上面的XML文档中,Side="1"表示卖方,Side="2"表示卖方。 现在,我想将上面的元素和属性存储在一个数组中,如下所示

阵列     国际标准书号     类型     PublishDate     Buyer_Company     Seller_Company     Buyer_Broker     Seller_Broker

我能够检索普通元素和属性,但不知道如何处理依赖于其他元素的属性     Buyer_Company     Seller_Company     Buyer_Broker     Seller_Broker 基于Side, Pty and Sub元素的Buyer_Company元素是Pty的ID属性R= 2 and Side=2。同样,Buyer_BrokerID元素的Sub属性,其属性Typ=26(可能存在Typ值不同的XML数据)和{{1} }元素已经是具有Sub的Pty元素的子元素,而R=1

时元素又是Book元素的子元素

用于检索独立元素的代码是

Side=2

我在单个元素中查询如下

var result = doc.Descendants("Book")
        .Select(b => new
        {
            ISBN= b.Attribute("ISBN").Value,
            Genre=b.Attribute("Genre").Value,
            PublishDate= b.Element("Title").Attribute("MMY").Value,        

        })
        .ToArray();

但是这并没有考虑元素 Company= (string)b.Descendants("Pty") .Where(e => (int)e.Attribute("R") == 7) .Select(e => e.Attribute("ID")) .Single() 中的属性Side

样本数据

第一本书元素

Book

第二本书元素

ISBN:1.1.1.1
Genre:Thriller
Seller_Company:NULL
Seller_Broker:NULL
Buyer_Company:ABC
Buyer_Broker:John

Side = 1表示卖方,side = 2表示买方,这就是卖方在第二个元素的第一个元素和第二个元素中的买方方面为空的原因

我知道更好的解决方法吗?

5 个答案:

答案 0 :(得分:2)

您可以使用Parent属性获取Parent的{​​{1}}元素,然后获取Pty属性并进行检查:

Side

答案 1 :(得分:2)

编辑以匹配问题:

使用XPath:

private static string GetCompanyValue(XElement bookElement, string side, string r)
{
  string format = "Title[@Side={0}]/Pty[@R={1}]";
  return GetValueByXPath(bookElement, string.Format(format, side, r));
}

private static string GetBrokerValue(XElement bookElement, string side)
{
  string format = "Title[@Side={0}]/Pty[@R=1]/Sub[@Typ=26]";
  return GetValueByXPath(bookElement, string.Format(format, side));
}

private static string GetValueByXPath(XElement bookElement, string expression)
{
  XElement element = bookElement.XPathSelectElement(expression);
  return element != null ? element.Attribute("ID").Value : null;
}

调用代码如下所示。

var result = doc.Descendants("Book")                            
                .Select(book => new
                {
                   ISBN = book.Attribute("ISBN").Value,
                   Genre = book.Attribute("Genre").Value,
                   Buyer_Company = GetCompanyValue(book, "2", "2"),
                   Buyer_Broker = GetBrokerValue(book, "2"),
                   Seller_Broker = GetBrokerValue(book, "1")
                })
                .ToArray();

using System.Xml.XPath;

添加using语句

答案 2 :(得分:1)

既然您已经提供了一些示例,我认为这对您有用。

const string xml =
    @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>    
    <Catalog>
    <Book ISBN=""1.1.1.1"" Genre=""Thriller"">
    <Title  Side=""1"">
    <Pty R=""1"" ID=""Seller_ID"">
        <Sub Typ=""26"" ID=""John"">
        </Sub>
    </Pty>
    <Pty R=""2"" ID=""ABC"">
    </Pty>
        </Title>
    </Book>
    <Book ISBN=""1.2.1.1"" Genre=""Thriller"">
    <Title  Side=""2"">
    <Pty R=""1"" ID=""Buyer_ID"">
        <Sub Typ=""26"" ID=""Brook"">
        </Sub>
    </Pty>
    <Pty R=""2"" ID=""XYZ"">
    </Pty>
        </Title>
    </Book>
    </Catalog>";
var doc = XDocument.Parse(xml);

var results = new List<object>();
foreach (var book in doc.Descendants("Book")) {
    var title = book.Element("Title");
    string buyerCompany = null;
    string buyerBroker = null;
    string sellerCompany = null;
    string sellerBroker = null;
    if (title.Attribute("Side").Value == "1") {
        sellerCompany = title.Elements("Pty")
            .Where(pty => pty.Attribute("R").Value == "2")
            .Select(pty => pty.Attribute("ID").Value)
            .FirstOrDefault();
        sellerBroker = title.Elements("Pty")
            .Where(pty => pty.Attribute("R").Value == "1")
            .Select(pty => pty.Element("Sub").Attribute("ID").Value)
            .FirstOrDefault();
    } else if (title.Attribute("Side").Value == "2") {
        buyerCompany = title.Elements("Pty")
            .Where(pty => pty.Attribute("R").Value == "2")
            .Select(pty => pty.Attribute("ID").Value)
            .FirstOrDefault();
        buyerBroker = title.Elements("Pty")
            .Where(pty => pty.Attribute("R").Value == "1")
            .Select(pty => pty.Element("Sub").Attribute("ID").Value)
            .FirstOrDefault();
    }

    var result = new {
        ISBN = book.Attribute("ISBN").Value,
        Genre = book.Attribute("Genre").Value,
        Seller_Company = sellerCompany,
        Seller_Broker = sellerBroker,
        Buyer_Company = buyerCompany,
        Buyer_Broker = buyerBroker,
    };

    results.Add(result);
}

结果:

result

答案 3 :(得分:0)

我想也许您想按ISBN分组,然后有选择地从孩子那里获取价值。

const string xml = 
    @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>    
    <Catalog>
        <Book ISBN=""1.1.1.1"" Genre=""Thriller"">
            <Title  Side=""1"" MMY=""000"">
                <Pty R=""1"" ID=""Seller_ID"">
                    <Sub Typ=""26"" ID=""Seller_Broker"">
                    </Sub>
                </Pty>
                <Pty R=""2"" ID=""Seller_Company"">
                </Pty>
            </Title>
        </Book>
        <Book ISBN=""1.1.1.1"" Genre=""Thriller"">
            <Title  Side=""2"">
                <Pty R=""1"" ID=""Buyer_ID"">
                    <Sub Typ=""26"" ID=""Buyer_Broker"">
                    </Sub>
                </Pty>
                <Pty R=""2"" ID=""Buyer_Company"">
                </Pty>
            </Title>
        </Book>
    </Catalog>";
var doc = XDocument.Parse(xml);
var results = doc.Descendants("Book")
    .GroupBy(x => x.Attribute("ISBN").Value)
    .Select(x => new {
        ISBN = x.Key,
        Genre = x.First().Attribute("Genre").Value,
        PublishDate = x.First().Element("Title").Attribute("MMY").Value,
        BuyerId = x.Where(book => book.Element("Title").Attribute("Side").Value == "2")
            .First()
            .Element("Title")
            .Element("Pty")
            .Attribute("ID").Value
    })
    .ToArray();

结果:

{
    ISBN = "1.1.1.1",
    Genre = "Thriller",
    PublishDate = "000",
    BuyerId = "Buyer_ID"
}

答案 4 :(得分:0)

尝试使用此方法进行完整解析

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            var result = doc.Descendants("Book")
                .Select(b => new
                {
                    ISBN = b.Attribute("ISBN").Value,
                    Genre = b.Attribute("Genre").Value,
                    Side = b.Element("Title").Attribute("Side").Value,
                    ptr = b.Element("Title").Elements("Pty").Select(x => new {
                        R = x.Attribute("R").Value,
                        PtyID = x.Attribute("ID").Value,
                        Typ = x.Elements("Sub").Select(y => y == null ? null : y.Attribute("Typ").Value).FirstOrDefault(),
                        SubIDTyp = x.Elements("Sub").Select(y => y == null ? null : y.Attribute("ID").Value).FirstOrDefault()
                    }).ToList()
                })
                .ToList();
        }
    }
}
​
相关问题