2015-07-15 2 views
0

Я пытаюсь получить данные из XML-документа в массив в C# с помощью LINQ, где мне нужно использовать некоторые вложенные запросы в элементах данных xml, которые следующие:Вложенный запрос XML-документа с использованием LINQ в C#

<?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" представляет собой торговую сторону. Теперь я хочу, чтобы хранить выше элементов и атрибутов в массиве, который, как поля следующим образом

Массив ISBN Жанр PublishDate Buyer_Company Seller_Company Buyer_Broker Seller_Broker

я был в состоянии восстановить нормальный элементов и атрибутов, но не был уверен, как справляться с атрибутами, которые зависят от других элементов, таких как Buyer_Company Seller_Company Buyer_Broker Продавец_Broker , которые составлены на основе Side, Pty and Sub элементов, таких как Buyer_Company is ID атрибут Pty, где R= 2 and Side=2. Точно так же, Buyer_Broker является ID атрибутом Sub элемента, где его атрибут Typ=26 (может быть XML-данными с другим значением Typ) и 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 

Вторая книга Элемент

ISBN:1.1.1.1 
Genre:Thriller 
Seller_Company:XYZ 
Seller_Broker:Brook 
Buyer_Company: NULL 
Buyer_Broker:NULL 

Side = 1 представляют собой продавец сторона и сторона = 2 представляет сторону покупателя, который почему сторона продавца имеет значение null в первом элементе результирующего массива и покупателя сторона во втором элементе

Могу ли я узнать лучший способ решить эту проблему?

ответ

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

2

Вы можете использовать Parent свойство, чтобы получить Parent элемент Pty затем получить атрибут Side и проверить его:

.Where(e => (int)e.Attribute("R") == 7 && 
      (int)e.Parent.Attribute("Side") == 2) 
+0

Спасибо, но когда я пытаюсь сохранить их в массиве в какой-то момент как на 'Side = 1 и Side = 2' либо' 'Buyer_Company' или Seller_Company' не будет содержать элементов, и в этом случае я просто хочу сохранить значение «NULL» – DoIt

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" 
} 
+0

Спасибо, но я хочу захватить как Buyer_Company, Seller_Company, так и Buyer_Broker, Seller_Broker для каждого элемента '', что делает один из них« NULL » – DoIt

+0

. Этот образец показывает вам как установить свойство с помощью элементов 'Pty' через' Book' ele которые фильтруются атрибутом 'side'. Если вы хотите пойти глубже, вы можете просто продолжить. т. е. добавить '.Element (" Sub ")' после '.Element (" Pty ")' для доступа к узлу Sub. –

+0

Кроме того, было бы полезно, если бы вы могли опубликовать пример свойств и ожидаемых значений из предоставленного XML-образца. Я только отправился в Buyer_ID, потому что мне было непонятно, чего вы ожидаете. –

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(); 
     } 
    } 
} 
​ 
2

Edited соответствовать вопрос:

Использование 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;

+0

Хорошая идея о Xpath. Эта мысль перешла мне в голову, когда я объединил эти элементы .Element()! –

+0

@Sarathy Ну, используя 'group by' и' First' возвращает только один элемент массива, тогда как я хочу проанализировать весь XML. Пожалуйста, взгляните на отредактированный вопрос для разных ISBN – DoIt

+0

@Sarathy. Помните, что я хотел бы проанализировать XML-файл enitre не только для первого из каждого 'ISBN' – DoIt

Смежные вопросы