Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб7.docx
Скачиваний:
10
Добавлен:
26.11.2019
Размер:
295.94 Кб
Скачать

1.4 Основные запросы (linq to xml)

Для возможности построение LINQ to XML запросов к проекту подключить библиотеку System.Xml.Linq;

Среди всех запросов LINQ to XML можно выделить ряд основных. 

1. Найти элемент с определенным атрибутом.

xmlLang

<?xml version="1.0"?>

<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">

<Address Type="Shipping">

<Name>Ellen Adams</Name>

<Street>123 Maple Street</Street>

<City>Mill Valley</City>

<State>CA</State>

<Zip>10999</Zip>

<Country>USA</Country>

</Address>

<Address Type="Billing">

<Name>Tai Yee</Name>

<Street>8 Oak Avenue</Street>

<City>Old Town</City>

<State>PA</State>

<Zip>95819</Zip>

<Country>USA</Country>

</Address>

<DeliveryNotes>Please leave packages in shed by

driveway.</DeliveryNotes>

<Items>

<Item PartNumber="872-AA">

<ProductName>Lawnmower</ProductName>

<Quantity>1</Quantity>

<USPrice>148.95</USPrice>

<Comment>Confirm this is electric</Comment>

</Item>

<Item PartNumber="926-AA">

<ProductName>Baby Monitor</ProductName>

<Quantity>2</Quantity>

<USPrice>39.98</USPrice>

<ShipDate>1999-05-21</ShipDate>

</Item>

</Items>

</PurchaseOrder>

В примере показано, как выполнить поиск элемента Address, имеющего атрибут Type со значением «Billing».

XElement root = XElement.Load("PurchaseOrder.xml");

IEnumerable<XElement> address =

from el in root.Elements("Address")

where (string)el.Attribute("Type") == "Billing"select el;

foreach (XElement el in address)

Console.WriteLine(el);

Этот код выводит следующие результаты.

xmlLang

<Address Type="Billing">

<Name>Tai Yee</Name>

<Street>8 Oak Avenue</Street>

<City>Old Town</City>

<State>PA</State>

<Zip>95819</Zip>

<Country>USA</Country>

</Address>

2. Найти элемент с определенным дочерним элементом.

xmlLang

<?xml version="1.0"?>

<Tests>

<Test TestId="0001" TestType="CMD">

<Name>Convert number to string</Name>

<CommandLine>Examp1.EXE</CommandLine>

<Input>1</Input>

<Output>One</Output>

</Test>

<Test TestId="0002" TestType="CMD">

<Name>Find succeeding characters</Name>

<CommandLine>Examp2.EXE</CommandLine>

<Input>abc</Input>

<Output>def</Output>

</Test>

<Test TestId="0003" TestType="GUI">

<Name>Convert multiple numbers to strings</Name>

<CommandLine>Examp2.EXE /Verbose</CommandLine>

<Input>123</Input>

<Output>One Two Three</Output>

</Test>

<Test TestId="0004" TestType="GUI">

<Name>Find correlated key</Name>

<CommandLine>Examp3.EXE</CommandLine>

<Input>a1</Input>

<Output>b1</Output>

</Test>

<Test TestId="0005" TestType="GUI">

<Name>Count characters</Name>

<CommandLine>FinalExamp.EXE</CommandLine>

<Input>This is a test</Input>

<Output>14</Output>

</Test>

<Test TestId="0006" TestType="GUI">

<Name>Another Test</Name>

<CommandLine>Examp2.EXE</CommandLine>

<Input>Test Input</Input>

<Output>10</Output>

</Test>

</Tests>

В этом примере осуществляется поиск элемента Test, имеющего дочерний элемент CommandLine со значением «Examp2.EXE».

XElement root = XElement.Load("TestConfig.xml");

IEnumerable<XElement> tests =

from el in root.Elements("Test")

where (string)el.Element("CommandLine") == "Examp2.EXE"select el;

foreach (XElement el in tests)

Console.WriteLine((string)el.Attribute("TestId"));

Этот код выводит следующие результаты.

0002

0006

3. Найти потомков элемента с определённым именем.

Иногда возникает необходимость найти всех потомков с определенным именем. В таких случаях можно написать код для просмотра всех потомков, но проще использовать ось xmlns="http://www.w3.org/1999/xhtml"Descendants.

В следующем примере показано, как находить потомков на основе имени элемента.

XElement root = XElement.Parse(@"<root>

<para>

<r>

<t>Some text </t>

</r>

<n>

<r>

<t>that is broken up into </t>

</r>

</n>

<n>

<r>

<t>multiple segments.</t>

</r>

</n>

</para>

</root>");

IEnumerable<string> textSegs =

from seg in root.Descendants("t")

select (string)seg;

string str = textSegs.Aggregate(new StringBuilder(),

(sb, i) => sb.Append(i),

sp => sp.ToString()

);

Console.WriteLine(str);

Этот код выводит следующие результаты:

Some text that is broken up into multiple segments.

4. Найти отдельного потомка.

Метод оси Descendants вы можете использовать для быстрого написания кода с целью поиска одного уникально именованного элемента. Этот способ особенно полезен, если нужно найти конкретного потомка с заданным именем. Можно написать собственный код для перехода к нужному элементу, но часто быстрей и легче написать такой код с помощью оси Descendants.

В этом примере используется стандартный оператор запроса First.

XElement root = XElement.Parse(@"<Root>

<Child1>

<GrandChild1>GC1 Value</GrandChild1>

</Child1>

<Child2>

<GrandChild2>GC2 Value</GrandChild2>

</Child2>

<Child3>

<GrandChild3>GC3 Value</GrandChild3>

</Child3>

<Child4>

<GrandChild4>GC4 Value</GrandChild4>

</Child4>

</Root>");

string grandChild3 = (string)

(from el in root.Descendants("GrandChild3")

select el).First();

Console.WriteLine(grandChild3);

Этот код выводит следующие результаты:

GC3 Value

5. Создать запросы с фильтрацией.

Иногда возникает необходимость в написании запросов LINQ to XML с комплексной фильтрацией. Например, может потребоваться найти все элементы, имеющие дочерние элементы с определенным именем и значением. В этом разделе приводится пример написания запроса с комплексной фильтрацией.

Пример

В этом примере показано, как найти все элементы PurchaseOrder, имеющие дочерний элемент Address с атрибутом Type, равным «Доставка», и дочерним элементом State, равным «NY». В нем используется вложенный запрос в предложении Where, а оператор Any возвращает значение true, если коллекция содержит элементы.

В этом примере выбирается несколько заказов на покупку (LINQ to XML).

xmlLang

<?xml version="1.0"?>

<PurchaseOrders>

<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">

<Address Type="Shipping">

<Name>Ellen Adams</Name>

<Street>123 Maple Street</Street>

<City>Mill Valley</City>

<State>CA</State>

<Zip>10999</Zip>

<Country>USA</Country>

</Address>

<Address Type="Billing">

<Name>Tai Yee</Name>

<Street>8 Oak Avenue</Street>

<City>Old Town</City>

<State>PA</State>

<Zip>95819</Zip>

<Country>USA</Country>

</Address>

<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>

<Items>

<Item PartNumber="872-AA">

<ProductName>Lawnmower</ProductName>

<Quantity>1</Quantity>

<USPrice>148.95</USPrice>

<Comment>Confirm this is electric</Comment>

</Item>

<Item PartNumber="926-AA">

<ProductName>Baby Monitor</ProductName>

<Quantity>2</Quantity>

<USPrice>39.98</USPrice>

<ShipDate>1999-05-21</ShipDate>

</Item>

</Items>

</PurchaseOrder>

<PurchaseOrder PurchaseOrderNumber="99505" OrderDate="1999-10-22">

<Address Type="Shipping">

<Name>Cristian Osorio</Name>

<Street>456 Main Street</Street>

<City>Buffalo</City>

<State>NY</State>

<Zip>98112</Zip>

<Country>USA</Country>

</Address>

<Address Type="Billing">

<Name>Cristian Osorio</Name>

<Street>456 Main Street</Street>

<City>Buffalo</City>

<State>NY</State>

<Zip>98112</Zip>

<Country>USA</Country>

</Address>

<DeliveryNotes>Please notify me before shipping.</DeliveryNotes>

<Items>

<Item PartNumber="456-NM">

<ProductName>Power Supply</ProductName>

<Quantity>1</Quantity>

<USPrice>45.99</USPrice>

</Item>

</Items>

</PurchaseOrder>

<PurchaseOrder PurchaseOrderNumber="99504" OrderDate="1999-10-22">

<Address Type="Shipping">

<Name>Jessica Arnold</Name>

<Street>4055 Madison Ave</Street>

<City>Seattle</City>

<State>WA</State>

<Zip>98112</Zip>

<Country>USA</Country>

</Address>

<Address Type="Billing">

<Name>Jessica Arnold</Name>

<Street>4055 Madison Ave</Street>

<City>Buffalo</City>

<State>NY</State>

<Zip>98112</Zip>

<Country>USA</Country>

</Address>

<Items>

<Item PartNumber="898-AZ">

<ProductName>Computer Keyboard</ProductName>

<Quantity>1</Quantity>

<USPrice>29.99</USPrice>

</Item>

<Item PartNumber="898-AM">

<ProductName>Wireless Mouse</ProductName>

<Quantity>1</Quantity>

<USPrice>14.99</USPrice>

</Item>

</Items>

</PurchaseOrder>

</PurchaseOrders>

XElement root = XElement.Load("PurchaseOrders.xml");

IEnumerable<XElement> purchaseOrders =

from el in root.Elements("PurchaseOrder")

where

(from add in el.Elements("Address")

where

(string)add.Attribute("Type") == "Shipping" &&

(string)add.Element("State") == "NY"select add)

.Any()

select el;

foreach (XElement el in purchaseOrders)

Console.WriteLine((string)el.Attribute("PurchaseOrderNumber"));

Этот код выводит следующие результаты:

99505

6. Отсортировать элементы.

В этом примере показано, как создавать запросы с сортировкой результатов.

Пример

xmlLang

<Root>

<TaxRate>7.25</TaxRate>

<Data>

<Category>A</Category>

<Quantity>3</Quantity>

<Price>24.50</Price>

</Data>

<Data>

<Category>B</Category>

<Quantity>1</Quantity>

<Price>89.99</Price>

</Data>

<Data>

<Category>A</Category>

<Quantity>5</Quantity>

<Price>4.95</Price>

</Data>

<Data>

<Category>A</Category>

<Quantity>3</Quantity>

<Price>66.00</Price>

</Data>

<Data>

<Category>B</Category>

<Quantity>10</Quantity>

<Price>.99</Price>

</Data>

<Data>

<Category>A</Category>

<Quantity>15</Quantity>

<Price>29.00</Price>

</Data>

<Data>

<Category>B</Category>

<Quantity>8</Quantity>

<Price>6.99</Price>

</Data>

</Root>

XElement root = XElement.Load("Data.xml");

IEnumerable<decimal> prices =

from el in root.Elements("Data")

let price = (decimal)el.Element("Price")

orderby price

select price;

foreach (decimal el in prices)

Console.WriteLine(el);

Этот код выводит следующие результаты:

0.99

4.95

6.99

24.50

29.00

66.00

89.99

7. Вычислить промежуточные значения.

В этом примере показано, как вычислять промежуточные значения, которые используются в сортировке, фильтрации и выборке.

В примере используется документ из примера 6 и предложение Let.

XElement root = XElement.Load("Data.xml");

IEnumerable<decimal> extensions =

from el in root.Elements("Data")

let extension = (decimal)el.Element("Quantity") *

(decimal)el.Element("Price")

where extension >= 25

orderby extension

select extension;

foreach (decimal ex in extensions)

Console.WriteLine(ex);

Этот код выводит следующие результаты:

55.92

73.50

89.99

198.00

435.00

8. Создать запрос для поиска элементов на основе контекста (выбор элементов на основе других элементов в дереве).

Иногда требуется написать запрос, который выбирает элементы, исходя из их контекста. Может потребоваться использовать фильтрацию с учетом предыдущих или следующих одноуровневых элементов. Может потребоваться использовать фильтрацию с учетом дочерних или родительских элементов.

Это можно сделать, написав запрос и используя результаты запроса в предложении where. Если требуется сначала провести проверку на наличие значения null, а затем проверить само значение, более удобным будет выполнить запрос в предложении let, а затем использовать результаты в предложении where.

Пример

В следующем примере выбираются все элементы class="code" p, сразу за которыми следует элемент ul.

XElement doc = XElement.Parse(@"<Root>

<p id=""1""/>

<ul>abc</ul>

<Child>

<p id=""2""/>

<notul/>

<p id=""3""/>

<ul>def</ul>

<p id=""4""/>

</Child>

<Child>

<p id=""5""/>

<notul/>

<p id=""6""/>

<ul>abc</ul>

<p id=""7""/>

</Child>

</Root>");

IEnumerable<XElement> items =

from e in doc.Descendants("p")

let z = e.ElementsAfterSelf().FirstOrDefault()

where z != null && z.Name.LocalName == "ul"select e;

foreach (XElement e in items)

Console.WriteLine("id = {0}", (string)e.Attribute("id"));

Этот код выводит следующие результаты:

id = 1

id = 3

id = 6

Другой вариант решения

XElement doc = XElement.Parse(@"<Root xmlns='http://www.adatum.com'>

<p id=""1""/>

<ul>abc</ul>

<Child>

<p id=""2""/>

<notul/>

<p id=""3""/>

<ul>def</ul>

<p id=""4""/>

</Child>

<Child>

<p id=""5""/>

<notul/>

<p id=""6""/>

<ul>abc</ul>

<p id=""7""/>

</Child>

</Root>");

XNamespace ad = "http://www.adatum.com";

IEnumerable<XElement> items =

from e in doc.Descendants(ad + "p")

let z = e.ElementsAfterSelf().FirstOrDefault()

where z != null && z.Name == ad.GetName("ul")

select e;

foreach (XElement e in items)

Console.WriteLine("id = {0}", (string)e.Attribute("id"));

Этот код выводит следующие результаты:

id = 1

id = 3

id = 6

 

Литература

  1. Общие сведения о программирования LINQ to XML. http://technet.microsoft.com/ru-ru/subscriptions/bb387065(v=vs.90).aspx

  2. http://msdn.microsoft.com/library/bb308960.aspx#xlinqoverview_topic2a

  3. http://msdn.microsoft.com/ru-ru/library/bb943906.aspx