Использование технологии LINQ 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Использование технологии LINQ



Лабораторная работа № 18

 

Использование технологии LINQ

для работы с данными

 

 

Время выполнения работы – 4 часа

 

 

 

Цель работы

Ознакомление с технологией LINO и ее использованием для работы с данными.

Техническое обеспечение

2.1 Персональная ЭВМ IBM Pentium III и более поздних моделей c оперативной памятью не менее 512 Мбайт.

2.2 Клавиатура.

2.3 Дисплей.

2.4 Манипулятор типа “мышь”.

Программное обеспечение

3.1 Операционная система Windows XP SP 3 более поздние версии Windows.

3.2 Система программирования Microsoft Visual Studio 2005 и более поздние версии.

Постановка задачи

Разработать Windows-приложения согласно варианта задания, которые приведены в разделе 6, используя табличный ввод и вывод данных.

 

Использование технологии LINQ

Технология LINQ (Language Integrated Query) предназначена для обработки (за­просов и преобразований) практически любого типа источника данных, начиная от массивов, файлов, строк, коллекций объектов.NET Framework, баз данных SQL Server, наборов данных ADO.NET (DataSet) и XML-документов. LINQ упрощает си­туацию, предлагая единообразные стандартные шаблоны для работы с данными в различных видах источников и форматов данных. Стандартные шаблоны включают в себя основные операции запросов LINQ: фильтрация, упорядочение, группировка, соединение, выбор (проецирование), статистическая обработка. По форме синтаксис языка LINQ очень похож на язык запросов SQL. В данной главе рассмотрим типич­ные LINQ-запросы и преобразования к некоторым источникам данных.

LINQ-запрос к массиву данных

LINQ-запрос представляет собой выражение, извлекающее данные из источни­ка данных. Все операции запроса LINQ состоят из трех различных действий: полу­чение источника (в нашем случае — это присвоение Начальных значений исходно­му массиву) данных, создание запроса (начинается с предложения from) и непосредственное выполнение запроса (обычно это цикл foreach). В данном раз­деле рассмотрим две задачи, первая — из массива имен извлекаем имена длиной шесть символов, записывая их или в список (коллекцию), или в новый массив. Дру­гая -задача— из массива целых чисел выбираем только те, значения которых больше четырех, также записывая результат запроса в список или массив.

Итак, запустим Visual Studio 2010, закажем новый проект шаблона Windows Forms Application С#. Затем из панели элементов перенесем в форму текстовое поле. Далее через щелчок правой кнопкой мыши перейдем к вкладке программного кода (листинг 19.1).

Листинг 19.1. Извлечение данных из массивов

// Решаем две задачи по выбору элементов из массива с помощью стандартных

// запросов технологии LINQ

using System;

using System.Linq;

using System.Windows.Forms;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace Linq1

{

public partial class Form1: Form

{

public Form1()

{

InitializeComponent();

this.Text = "Технология LINQ"; textBox1.Multiline = true;

// ЗАДАЧА 1:

// Из массива имен выбрать имена с количеством букв равным шести,

// вывести эти имена в текстовое поле TextBox в алфавитном порядке, при

// этом все буквы перевести в верхний регистр.

// Решение:

string СтрокаИмен = "Витя Лариса Лариса Лена Андрей Женя " +

"Александр Лариса Виктор Света Оксана Наташа";

// Из строки имен получаем массив имен, задавая в качестве сепаратора

// деления подстрок символ пробела:

string[] Имена = СтрокаИмен.Split(' ');

// или проще: string[] Имена =

// { "Витя", "Лариса", "Лариса", "Лена", "Андрей", "Женя",

// "Александр", "Лариса", "Виктор", "Света", "Оксана", "Наташа" };

textBox1.Text = "ЗАДАЧА 1. В списке имен:\r\n\r\n";

foreach (string x in Имена)

textBox1.Text = textBox1.Text + x + " ";

// В результате LINQ-запроса получаем список имен с количеством букв

// равным шести:

var Запрос = from s in Имена

where s.Length == 6 // - условие выбора

orderby s // - сортировать в алфавитном порядке

select s.ToUpper(); // - перевод в верхний регистр

// s - это переменная диапазона схожа с переменной итерации в foreach

// Удаляем элементы-дубликаты из списка имен:

Запрос = Запрос.Distinct();

// Или таким образом:

// Запрос = Запрос.Union(Запрос);

textBox1.Text = textBox1.Text + "\r\n\r\n" +

"выбираем имена с количеством букв равным шести, при " +

"этом избавляемся от дублирования имен:\r\n\r\n";

foreach (string x in Запрос) // x - переменная итерации в цикле foreach

textBox1.Text = textBox1.Text + x + " ";

textBox1.Text = textBox1.Text + "\r\n\r\n";

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ЗАДАЧА 2: Из массива целых чисел X[] требуется выбрать числа,

// значения которых >= 4, и записать эти числа в список Y,

// отсортировав выбранные числа по возрастанию.

// Решение:

// Инициализация массива целых чисел:

int[] X = { -2, 5, -23, 0, 7, -10, 11, 11, 14, 3, 8, 5, -5, 27, 8 };

textBox1.Text += "ЗАДАЧА 2. Из заданного массива X:\r\n\r\n";

foreach (int x in X)

textBox1.Text = textBox1.Text + x + " ";

textBox1.Text = textBox1.Text + "\r\n\r\nвыбираем числа, значения " +

"которых >= 4 и записываем их в список (коллекцию) Y, " +

"исключая элементы-дубликаты:\r\n\r\n";

// Y - это список, куда помещается выбранные элементы:

var Y = from x in X

where x >= 4 // - условие выбора

orderby x // - сортируем по возрастанию

select x;

// Таким образом можно получить результат запроса в массив:

// int[] Y = (from x in X // Здесь Y - это уже массив;

// where x >= 4 // - условие выбора;

// orderby x // - сортируем по возрастанию;

// select x).ToArray(); // - преобразование списка в массив

// Удаляем элементы-дубликаты из списка целых чисел:

var Z = Y.Distinct();

// Или таким образом:

// var Z = Y.Union(Y);

// Вывод элементов списка Y в метку textBox1:

foreach (var z in Z)

textBox1.Text = textBox1.Text + z.ToString() + " ";

}

}

}

Как видно из программного кода, после присвоения массиву Имена начальных значений создаем запрос, который предусматривает выбор (select) из (from) мас­сива Имена строк длиной (Length) ровно шесть символов (условие where). Запись выбранных имен выполняется в список Запрос с сортировкой списка в алфавитном порядке имен. Далее для удаления повторяющихся имен в списке используем функцию Distinct. В комментарии показано, как можно для этой же цели исполь­зовать функцию union, которая, вообще говоря, находит объединение двух мно­жеств, т. е. выбирает в двух списках одинаковые элементы с удалением повторяю­щихся элементов. Поскольку мы объединяем два одинаковых списка, то получаем просто удаление повторяющихся элементов. Цикл foreach выводит список Запрос в текстовое поле textBox1.

Следующая задача, решенная в данном программном коде, аналогична. Задан массив целых чисел X. Из этого массива выбираем в список Y элементы массива, значения которых больше или равны четырем. В комментарии показано, как можно записать результаты LINQ-запроса в массив. Удаление повторяющихся элементов в списке выполнено также с использованием функции Distinct.

На рис. 19.1 приведен фрагмент работы программы.

 

Рисунок 19.1 - LINQ-запросы к массивам данных

Убедиться в работоспособности программы можно, открыв решение Linq1.sln папки Linq1.

Листинг 19.2. Извлечение данных из списков

// Решаем три различных задачи по выбору элементов (объектов) из списка с помощью

// стандартных запросов технологии LINQ

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows.Forms;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace Linq2

{

public partial class Form1: Form

{

public Form1()

{

InitializeComponent();

this.Text = "Технология LINQ"; textBox1.Multiline = true;

// ЗАДАЧА 1. Из списка строк выбрать нужные записи задав условие выбора

textBox1.Text = "ЗАДАЧА 1: Из списка имен:\r\n";

// Объявление списка строк и его заполнение:

var Список = new List<string> { "Витя", "Света", "Андрей",

"Лариса", "Маша", "Наташа" };

// или var Список = new List<string>(); // - список строк

// Список.Add("Витя"); Список.Add("Света"); Список.Add("Андрей");

// Список.Add("Лариса"); Список.Add("Маша"); Список.Add("Наташа");

// Некоторые манипуляции со списком:

int n = Список.Count; // Кол-во элементов в списке:

// Получение из списка его элемента с индесом 3 (как в массиве):

string A = Список.ElementAt<string>(4);

Boolean Ответ = Список.Remove("Лариса"); // - удаление из списка

// Преобразовать список в строковый массив:

string[] МассивСтрок = Список.ToArray();

foreach (var x in Список)

textBox1.Text = textBox1.Text + x.ToString() + " ";

textBox1.Text += "\r\nвыбираем имена длиной четыре символа:\r\n";

// СписокВыбранныхИмен - это новый список, куда попадают выбранные

// строки в результате LINQ-запроса:

var СписокВыбранныхИмен = from Имя in Список

where Имя.Length == 4 // - условие выбора

orderby Имя // - сортировать список Z

select Имя;

// Вывод списка выбранных имен в текстовое поле textBox1:

foreach (var x in СписокВыбранныхИмен)

textBox1.Text = textBox1.Text + x.ToString() + " ";

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ЗАДАЧА 2.

textBox1.Text +=

"\r\n\r\nЗАДАЧА 2: Из списка сотрудников предприятия " +

"выбираем не курящих для повышения зарплаты:\r\n\r\n";

// Заполняем список сотрудников:

List<Сотрудник> Сотрудники = new List<Сотрудник>{

new Сотрудник {Имя="Карапузова Ирина", Возраст=27, КуритЛи=true },

new Сотрудник {Имя="Зиборов Виктор", Возраст=47, КуритЛи=false },

new Сотрудник {Имя="Ломачинская Светлана", Возраст=34,

КуритЛи=false },

new Сотрудник {Имя="Стороженко Светлана", Возраст=34, КуритЛи=false },

new Сотрудник {Имя="Еременко Татьяна", Возраст=34, КуритЛи=true },

new Сотрудник {Имя="Погребицкий Олег", Возраст=42, КуритЛи=true },

};

var СписокНекурящихСотрудников = from Сотрудник in Сотрудники

where Сотрудник.КуритЛи == false

orderby Сотрудник.Имя

select Сотрудник;

// Вывод списка некурящих сотрудников в текстовое поле textBox1:

foreach (var x in СписокНекурящихСотрудников)

textBox1.Text = textBox1.Text + string.Format("{0} - возраст " +

"- {1}\r\n", x.Имя, x.Возраст);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// ЗАДАЧА 3.

textBox1.Text += "\r\nЗАДАЧА 3: Из списка студентов факультета " +

"выбираем двоечников:\r\n\r\n";

// Каждый элемент в списке содержит фамилию студента и полученные

// им текущие оценки:

List<Студент> Студенты = new List<Студент>

{

new Студент {Фамилия="Зиборов", Оценки= new List<int> {5, 4, 4, 5}},

new Студент {Фамилия="Стороженко", Оценки= new List<int> {3, 3, 2, 3}},

new Студент {Фамилия="Ломачинская", Оценки= new List<int> {3, 4, 4, 5}},

new Студент {Фамилия="Погребицкий", Оценки= new List<int> {2, 4, 3, 2}},

new Студент {Фамилия="Левочкин", Оценки= new List<int> {3, 3, 4, 3}}

};

// Для доступа к внутреннему списку оценок предложение From

// используем два раза:

var СписокДвоечников = from Студент in Студенты

from Оценка in Студент.Оценки

where Оценка <= 2

orderby Студент.Фамилия

select new { Студент.Фамилия, Оценка };

foreach (var Студик in СписокДвоечников)

textBox1.Text += string.Format("Студент {0} " +

"имеет оценку: {1}\r\n", Студик.Фамилия, Студик.Оценка);

// Строка со студентом Погребицким выводится два раза, поскольку он

// имеет две двойки

}

}

// Объявляем класс, содержащий имя сотрудника, его возраст, а также

// информацию, курит ли он:

public class Сотрудник

{

public string Имя { get; set; }

public int Возраст { get; set; }

public bool КуритЛи { get; set; }

}

// Объявляем класс, содержащий фамилию студента и список полученных им оценок:

public class Студент

{

public string Фамилия { get; set; }

public List<int> Оценки { get; set; }

}

}

 

Первая задача довольно простая и очень похожа на задачи, которые мы решали с помощью технологии LINQ в предыдущем примере. Здесь, в этой новой задаче вместо массива имен требуется создать список имен, а далее из этого списка вы­брать имена длиной четыре символа. Решение этой задачи, построение LINQ- запроса аналогично решению задачи из предыдущего примера, отличие состоит лишь в применении синтаксиса манипуляций со списком типа List, а не с масси­вом. Здесь также приведены некоторые важные техники для манипуляции списком, в частности получение элемента списка по указанному индексу (аналогия с масси­вом), удаление элемента, преобразование списка в строковый массив.

Вторая задача заключается в том, чтобы создать список сотрудников предпри­ятия и из этого списка выбрать некоторых сотрудников по какому-либо признаку, например тех, кто не курит. При создании списка объявлен класс Сотрудник, кото­рый содержит три свойства: Имя, Возраст и булеву переменную КуритЛи. В начале решения заполняем список сотрудников, а затем строим LINQ-запрос для заполне­ния списка некурящих сотрудников. Этот список выводим в текстовое поле textBox1, используя цикл foreach.

Третья задача немного сложнее. Требуется создать список студентов факульте­та, содержащий фамилию студента и список полученных им текущих оценок, т. е. список оценок должен быть "вложен" в список студентов. Из списка студентов не­обходимо выбрать тех, кто имеет в списке своих оценок хотя бы одну двойку. Для решения этой задачи вначале объявляем новый класс Студент, который имеет в ка­честве свойств класса фамилию студента и список (типа List) оценок. Далее в на­чале решения третьей задачи мы привели синтаксис заполнения списка студентов. Затем строим LINQ-запрос, где, поскольку нам необходимо искать элемент списка внутри "вложенного" списка, мы используем предложение From два раза. Посколь­ку студент Погребицкий имеет две двойки в списке своих текущих оценок, он в списке двоечников фигурирует дважды (рис. 19.2).

Рисунок 19.2 - Три LINQ-запроса к спискам данных

Убедиться в работоспособности программы можно, открыв решение Linq2.sln папки Linq2.

Листинг 19.3. Группировка элементов списка с помощью LINQ-запросов

// Программа формирует список некоторых продуктов питания. Первый LINQ-запрос

// группирует элементы списка по критерию цены: в первом списке оказываются

// продукты, цена за единицу которых меньше или равна 90 руб., а во втором,

// соответственно, больше 90 руб. Второй LINQ-запрос вычисляет среднюю цену

// продукта по каждой группе. Результаты запросов выводятся в текстовое поле.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows.Forms;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace LinqЦеныНаПродукты

{

public partial class Form1: Form

{

public Form1()

{

InitializeComponent();

textBox1.Multiline = true;

base.Text = "Группировка элементов списка с помощью LINQ-запроса";

// Заполняем список продуктов:

List<Продукт> Продукты = new List<Продукт>{

new Продукт {Наименование="Творог", Цена=112.50F },

new Продукт {Наименование="Хлеб", Цена=18.75F },

new Продукт {Наименование="Печенье", Цена=93.75F },

new Продукт {Наименование="Чай", Цена=76.25F },

new Продукт {Наименование="Мясо", Цена=150.00F },

new Продукт {Наименование="Гречка", Цена=62.50F },

};

var Запрос1 =

from П in Продукты

group П by new

{

Критерий = П.Цена > 90,

}

into g

select g;

var Запрос2 =

from p in Продукты

group p by p.Цена > 90 into g

select new

{

g.Key,

СредЦенаПоГруппе = g.Average(p => p.Цена)

};

Single СредЦенаПоГруппе1 = Запрос2.ElementAt(0).СредЦенаПоГруппе;

Single СредЦенаПоГруппе2 = Запрос2.ElementAt(1).СредЦенаПоГруппе;

// Вывод результатов обоих запросов в текстовое поле:

foreach (var Группа in Запрос1)

{

if (Группа.Key.Критерий == false)

textBox1.Text += "\r\nЦены 90 руб или меньше:";

else

textBox1.Text += "\r\nЦены больше 90 руб:";

foreach (var Прод in Группа)

{

textBox1.Text += String.Format("\r\n{0} - {1}",

Прод.Наименование, Прод.Цена);

}

if (Группа.Key.Критерий == false)

textBox1.Text += String.Format(

"\r\nСредняя цена по данной группе = {0} руб.\r\n",

СредЦенаПоГруппе2);

else

textBox1.Text += String.Format(

"\r\nСредняя цена по данной группе = {0} руб.\r\n",

СредЦенаПоГруппе1);

}

}

}

public class Продукт

{

public String Наименование { get; set; }

public Single Цена { get; set; }

}

}

В начале программы формируем список продуктов питания. Для этого объяв­ляем новый класс продукт, в котором для каждого продукта задаем два поля: на­именование продукта и его цену. После заполнения списка продуктов (для упро­щения в этом списке всего шесть продуктов) задаем первый LINQ-запрос, обеспечивающий деление списка на две группы. Второй LINQ-запрос вычисляет среднюю цену продукта по каждой группе. Вывод результатов обоих запросов ор­ганизуем с помощью двух вложенных циклов foreach.

Фрагмент работы программы показан на рис. 19.3.

Рисунок 19.3 - Группировка списка с помощью LINQ-запросов

Убедиться в работоспособности программы можно, открыв решение LinqЦеныНаПродукты.sln папки LinqЦеныНаПродукты.

5.4 LINQ-запрос к словарю данных Dictionary

Замечательной структурой данных является словарь Dictionary. Он представ­ляет собой совокупность (коллекцию) ключей и значений. То есть каждый элемент (запись), добавляемый в словарь, состоит из значения Value и связанного с ним ключа Key. Извлечение значения по его ключу происходит очень быстро, посколь­ку класс Dictionary<Key,Value> реализован как хэш-таблица. Каждый ключ в словаре Dictionary<Key,Value> должен быть уникальным, т. е. единственным в своем роде, эксклюзивным. При добавлении в коллекцию Dictionary очередного элемента так называемый компаратор проверяет на равенство уникальность нового ключа. Ключ не может быть пустым (null), а значение может, если тип значения value является ссылочным типом. Возможно создание словаря, в котором не раз­личается регистр символов. Использование словаря Dictionary может существен­но повлиять на эффективность алгоритма, на простоту его понимания и легкость программной реализации.

Задача, решаемая в данном примере, состоит в том, чтобы продемонстрировать возможность выбора элементов из словаря данных Dictionary с помощью LINQ-запроса. В начале программы зададим массив сотрудников некого учреждения, а затем массив сотрудников преобразуем в словарь Dictionary. Причем в качестве ключа к каждому элементу словаря зададим имя сотрудника, которое является уни­кальным. По ключу можно получить все остальные сведения о сотруднике, запи­санные в словарь. Кроме того, с помощью LINQ-запроса к словарю можно полу­чать новую коллекцию сотрудников по какому-либо условию (предложение where). Здесь мы зададим выбор сотрудников, чей возраст превышает 33 года (возраст Ии­суса Христа). ’

Для решения этой задачи запустим Visual Studio 2010 и выберем проект шабло­на Console Application, укажем имя Name — LinqDictionary. Затем на вкладке про­граммного кода введем текст, представленный в листинге 19.4.

Листинг 19.4. Организация LINQ-запроса к словарю Dictionary

// Задаем массив сотрудников учреждения. Из этого массива создаем словарь

// сотрудников, а в качестве ключа к этому словарю выбираем имя сотрудника.

// С помощью LINQ-запроса из массива сотрудников выбираем тех, чей возраст

// превышает 35 лет. При выводе результата запроса на печать учитываем, что

// говоря про возраст, мы говорим "47 лет", но "34 года". То есть если из возраста

// вычесть число кратное 10, то при остатке меньше 5, говорят, например, "34 года",

// а при остатке больше или равно 5, говорят "47 лет".

using System;

using System.Linq;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace LinqDictionary

{

class Program

{

static void Main(string[] args)

{

Console.Title = "LINQ-запрос к словарю Dictionary";

// Создаем массив сотрудников учреждения:

var Сотрудники = new[] {

new {Имя = "Карапузова Ирина", Возраст = 27, КуритЛи = true },

new {Имя = "Зиборов Виктор", Возраст = 47, КуритЛи = false },

new {Имя = "Ломачинская Светлана", Возраст = 31, КуритЛи = false },

new {Имя = "Стороженко Светлана", Возраст = 34, КуритЛи = false },

new {Имя = "Еременко Татьяна", Возраст = 22, КуритЛи = true },

new {Имя = "Погребицкий Олег", Возраст = 42, КуритЛи = true }

};

// Доступ к элементу массива Сотрудники можем иметь через его индекс:

var t = Сотрудники[2];

// Строим LINQ-запрос к массиву сотрудников; выбираем тех, возраст

// которых больше 33 лет:

// var СписокВзрослыхСотрудников = from Сотрудник in Сотрудники

// where Сотрудник.Возраст >= 33

// orderby Сотрудник.Имя

// select Сотрудник;

// Из массива сотрудников создаем словарь сотрудников, в котором

// ключом является имя сотрудника:

var СловарьСотрудников = Сотрудники.ToDictionary(Ключ => Ключ.Имя);

// В этом случае очень удобным становится доступ к сведениям о

// сотруднике по его имени:

Boolean КуритЛиЗиборов = СловарьСотрудников["Зиборов Виктор"].КуритЛи;

int ВозрастЗиборова = СловарьСотрудников["Зиборов Виктор"].Возраст;

Console.WriteLine("Сотруднику Зиборову Виктору - {0} лет\n",

ВозрастЗиборова);

// Строим LINQ-запрос к словарю сотрудников; выбираем тех, возраст

// которых больше 33 лет:

var СписокВзрослыхСотрудников =

from Сотрудник in СловарьСотрудников

where Сотрудник.Value.Возраст >= 33

orderby Сотрудник.Value.Имя

select new

{

Сотрудник.Key,

Сотрудник.Value.Возраст,

ЛетИлиГода = Сотрудник.Value.Возраст - 10F *

Math.Truncate(Сотрудник.Value.Возраст / 10F) >= 5

};

 

// Вывод результата запроса на консоль:

Console.WriteLine("Список сотрудников, старше 33 лет:");

foreach (var x in СписокВзрослыхСотрудников)

Console.WriteLine("{0}, возраст - {1} {2} ", x.Key, x.Возраст,

x.ЛетИлиГода? "лет": "года");

Console.ReadKey();

}

}

}

Представленный текст программы очевиден. Вначале задаем массив сотрудни­ков учреждения, в этом массиве всего 6 элементов. В комментарии показано, как можно организовать LINQ-запрос к заданному массиву. Далее массив конвертиру­ем в словарь сотрудников, задавая в качестве ключа имя сотрудника. Затем органи­зуем LINQ-запрос к словарю Dictionary, выбираем в новую коллекцию (список) тех, чей возраст превышает 33 года. Учитываем, что при выводе на консоль списка выбранных сотрудников мы говорим "47 лет", но "34 года". То есть если из возрас­та вычесть число, кратное 10, то при остатке меньше 5 говорят, например, "34 го­да", а при остатке больше или равном 5 говорят "47 лет". Число, кратное 10, мы вычисляем, используя функцию Math.Truncate, которая возвращает целую часть числа, поданную на ее вход. В этом алгоритме мы использовали булеву перемен­ную ЛетИлиГода, которая определяет (по принципу "да" или "нет") следует писать "лет" или "года".

Результат работы программы показан на рис. 19.4

 

 

Рисунок 19.4 - Запрос к словарю данных на "взрослых" сотрудников

Убедиться в работоспособности программы можно, открыв решение LinqDic- tionary.sln папки LinqDictionary.

Листинг 19.5. Создание XML-документа представляющего телефонную книгу.

// Программа создает типичный XML-документ. С ее помощью можно разобраться в

// структуре XML-документа. В комментариях приведена терминология содержимого

// XML-документа: корневой элемент, вложенные элементы, имя элемента и его

// значение, а также атрибуты элемента, их имена и значения.

// XML-документ представляет телефонную книгу, содержащую имя контакта, номер

// домашнего телефона, а также мобильного. Программа после создания XML-документа

// отображает его на консоли, а также записывает его в файл. Если этот файл открыть

// с помощью MS Excel, то мы получим таблицу из трех столбцов.

using System;

using System.Xml.Linq;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace LinqСоздатьXML_документ

{

class Program

{

static void Main(string[] args)

{

Console.Title = "Корневой элемент XML-документа";

// Создаем новый XML-документ:

XDocument XMLдокумент = new XDocument(

// Комментарий в XML-документе:

new XComment("Телефонная_книга - это корневой элемент XML-документа:"),

new XElement("Телефонная_книга", // - имя корневого элемента

 

new XComment("Элемент СТРОКА содержит атрибут Контакт и два вложенных элемента"),

new XElement("СТРОКА", // - имя (Name) элемента

new XAttribute("Контакт", "Олег"),

new XElement("Домашний_телефон", "236-23-67"), // - имя элемента и его значение

new XElement("Мобильный_телефон", "+7(495)625-31-43")),

 

new XComment("Атрибут Контакт имеет значение 'Прогноз погоды':"),

new XElement("СТРОКА",

new XAttribute("Контакт", "Прогноз погоды"), // - атрибут элемента СТРОКА

new XElement("Домашний_телефон", "001"),

new XElement("Мобильный_телефон", "")), // - имя элемента и его зачение (Value)

 

new XComment("Поскольку каждый элемент Контакт имеет атрибут и два вложенных=>"),

new XElement("СТРОКА",

new XAttribute("Контакт", "Борис Григорьевич"), // - имя атрибута - Контакт

new XElement("Домашний_телефон", "402-12-45"),

new XElement("Мобильный_телефон", "+7(495)536-79-94")),

 

new XComment("=> элемента, в MS Excel отобразится таблица с тремя колонками"),

new XElement("СТРОКА",

new XAttribute("Контакт", "Света"), // - значение атрибута - Света

new XElement("Домашний_телефон", ""),

new XElement("Мобильный_телефон", "+7(495)615-24-41")))

);

// Сохранить XML-документ:

XMLдокумент.Save(@"C:\Зиборов.XML");

Console.WriteLine(XMLдокумент);

Console.ReadKey();

}

}

}

 

Чтобы понять текст программы, рассмотрим структуру полученного XML- файла, а для этого откроем этот файл с помощью Internet Explorer (рис. 19.5).

Здесь весь XML-документ вложен в так называемый корневой элемент между начальным тегом <Телефонная_книга> и конечным тегом </Телефонная_книга>. Четыре элемента СТРОКА вложены в корневой элемент. В соответствующей таблице MS Excel элементы СТРОКА будут представлять строку в таблице. В свою очередь элемент СТРОКА содержит в себе атрибут Контакт и два вложенных в него элемента, имена (Name) которых— Домашний_телефон и Мобильный_телефон. Именно поэтому в MS Excel отобразится таблица с тремя колонками (один атрибут и два элемента): "Контакт", "Домашний_телефон" и "Мобильный_телефон".

Элемент может иметь один или несколько атрибутов (а может и не иметь, как, скажем, элемент Домашний_телефон), например, первый элемент СТРОКА имеет ат­рибут с именем (Name) Контакт и со значением атрибута (Value) — 001.

После запуска данной программы будет выведено на консоль содержимое XML-документа (без XML-объявления), а также будет создан XML-файл. Открыв этот файл с помощью MS Excel, получим таблицу телефонных контактов (рис. 19.6).

 

 

Рисунок 19.5 - XML-файл, открытый в Internet Explorer

 

Рисунок 19.6 - XML-файл, открытый в MS Excel

Убедиться в работоспособности программы можно, открыв решение LinqСоздатьXML-документ.sln папки LinqСоздатьXML-документ.

Листинг 19.6. Извлечение значения элемента из XML-данных

// Дана строка XML, содержащая прогнозные метеорологические показатели для

// г. Москвы на заданную дату. Программа извлекает из корневого элемента

// XML-документа значение температуры элемента "Температура":

using System.Windows.Forms;

//Другие директивы using удалены, поскольку они не используются в данной программе

namespace Linq3

{

public partial class Form1: Form

{

public Form1()

{

InitializeComponent();

this.Text = "LINQ-запрос к XML-данным"; textBox1.Multiline = true;

string СтрокаXML =

@"<?xml version=""1.0""?>

<МетеорологическиеПоказатели>

<Город>Москва</Город>

<Дата>2010.05.15 06:30 UTC</Дата>

<Температура> 64 F (18 C)</Температура>

<Ветер>Сев-Вост 8 м/сек</Ветер>

<Видимость>12 км</Видимость>

<Влажность> 72%</Влажность>

<Давление>760 мм рт ст</Давление>

</МетеорологическиеПоказатели>";

// Загрузка корневого элемента из строки, содержащей XML:

var КорневойЭлемент = System.Xml.Linq.XElement.Parse(СтрокаXML);

// Или корневой элемент XML-документа получаем через файл:

// Записываем строку, содержащую XML в файл:

// System.IO.File.WriteAllText("ПоказателиПогоды.xml", СтрокаXML);

// Загружаем корневой элемент XML:

// var КорневойЭлемент = System.Xml.Linq.

// XElement.Load("ПоказателиПогоды.xml");

// Из корневого элемента извлекаем вложенный в него элемент

// "Температура" и получаем соответствующее значение (Value) этого

// элемента:

string Температура = КорневойЭлемент.Element("Температура").Value;

textBox1.Text = "Строка XML:\r\n\r\n" + СтрокаXML + "\r\n\r\n";

textBox1.Text += "Значение температуры = " + Температура;

}

}

}

В начале текста программы задаем текстовую строку, содержащую XML- данные. Далее, используя метод Parse класса XElement пространства имен Linq, получаем корневой элемент XML-документа. В комментарии показано, как можно получить корневой элемент через запись/чтение XML-файла. Затем с помощью ме­тода Element извлекаем значение (Value) элемента температура, которое выводим в текстовое поле.

Фрагмент работы программы приведен на рис. 19.8.

Рисунок 19.8 - Извлечение значения элемента из XML-документа

Рисунок 19.9 - Представление XML-данных в виде таблицы в MS Excel

Убедиться в работоспособности программы можно, открыв решение Linq3.sln папки Linq3.

Теперь решим похожую задачу по извлечению значения элемента, но пусть XML-данные представлены в другой форме, а именно каждый метеорологический показатель вложим в один и тот же элемент <Показатель> </Показатель>, в этом случае глубина вложенности элементов будет уже равна трем (см. листинг 19.7). Естественно спросить: что мы будем с этого иметь? Дело в том, что если соответ­ствующий XML-файл открыть с помощью табличного редактора MS Excel, то мы сможем увидеть эти XML-данные в виде наглядной таблицы, даже не ссылаясь на таблицу стилей — файл XSLT (не путать с XLS-файлом), см. рис. 19.9.

Теперь для получения значения температуры удобно воспользоваться типовым LINQ-запросом (листинг 19.7).

Листинг 19.7. Извлечение значения элемента из XML-данных

// Дана строка XML, которая содержит прогнозные метеорологические показатели для

// г. Москвы на заданную дату. При этом каждый метеорологический показатель вложен

// в один и тот же элемент <Показатель> </Показатель>. Это обеспечивает удобный

// просмотр соответствующего XML-файла в MS Excel в виде таблицы. Программа находит

// в корневом элементе данного XML-документа элемент "Температура" и извлекает из

// него значение температуры.

using System.Windows.Forms;

using System.Linq;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace Linq4

{

public partial class Form1: Form

{

public Form1()

{

InitializeComponent();

this.Text = "LINQ-запрос к XML-данным"; textBox1.Multiline = false;

// Инициализация XML-строки:

string СтрокаXML =

@"<?xml version=""1.0""?>

<МетеорологическиеПоказатели>

<Показатель>

<Город>Москва</Город>

</Показатель>

<Показатель>

<Дата>2010.05.15 06:30 UTC</Дата>

</Показатель>

<Показатель>

<Температура> 64 F (18 C)</Температура>

</Показатель>

<Показатель>

<Ветер>Сев-Вост 8 м/сек</Ветер>

</Показатель>

<Показатель>

<Видимость>12 км</Видимость>

</Показатель>

<Показатель>

<Влажность> 72%</Влажность>

</Показатель>

<Показатель>

<Давление>760 мм рт ст</Давление>

</Показатель>

</МетеорологическиеПоказатели>";

var КорневойЭлемент = System.Xml.Linq.XElement.Parse(СтрокаXML);

// Или корневой элемент получаем через файл:

// Записываем строку, содержащую XML в файл:

// System.IO.File.WriteAllText("ПоказателиПогоды2.xml", СтрокаXML);

// Загружаем корневой элемент:

// var КорневойЭлемент = System.Xml.Linq.XElement.Load(

// "ПоказателиПогоды2.xml");

// Запрос - это коллекция (список) строк, куда извлекаем значение

// (Value) элемента "Температура":

var Запрос = from x in КорневойЭлемент.Elements("Показатель")

from y in x.Elements("Температура")

select y.Value;

// Таких строк в коллекции Запрос - одна

textBox1.Text = "Значение температуры = ";

foreach (var x in Запрос)

textBox1.Text = textBox1.Text + x;

}

}

}

Как видно из программного кода, поиск организован в двух уровнях (два пред­ложения from), сначала выбор в коллекцию всех элементов Показатель, а затем из этой коллекции поиск элементов Температура. Результат запроса записывается в коллекцию строк, где имеем ровно одну строку. Фрагмент работы программы по­казан на рис. 19.10.

Рисунок 19.10 - LINQ-запрос к XML-документу

Убедиться в работоспособности программы можно, открыв решение Linq4.sln из папки Linq4.

Листинг 19.8. Извлечение значения элемента из XML-данных

// Имеем XML-данные, в которых содержатся таблица с именами и телефонами, причем

// имена в этой телефонной табличке повторяются. Задача состоит в том, чтобы в

// данной таблице телефонов (представленной в виде XML) найти все строчки c

// именем "Витя" с помощью LINQ-запроса.

using System.Linq;

using System.Windows.Forms;

// Другие директивы using удалены, поскольку они не используются в данной программе

namespace Linq5

{

public partial class Form1: Form

{

public Form1()

{

InitializeComponent();

this.Text = "LINQ-запрос к XML-данным"; textBox1.Multiline = true;

// Инициализация XML-строки:

string СтрокаXML =

@"<?xml version=""1.0""?>

<ТаблицаТелефонов>

<Строка>

<Имена>Витя</Имена>

<Номера_телефонов>274 28 44</Номера_телефонов>

</Строка>

<Строка>

<Имена>Андрей</Имена>

<Номера_телефонов>8-085-456-2378</Номера_телефонов>

</Строка>

<Строка>

<Имена>Карапузова Таня</Имена>

<Номера_телефонов>445-56-47</Номера_телефонов>

</Строка>

<Строка>

<Имена>Витя</Имена>

<Номера_телефонов>099 72 161 52</Номера_телефонов>

</Строка>

<Строка>

<Имена>Никипелов</Имена>

<Номера_телефонов>236-77-76</Номера_телефонов>

</Строка>

<Строка>

<Имена>Зиборов</Имена>

<Номера_телефонов>254 67 97</Номера_телефонов>

</Строка>

</ТаблицаТелефонов>";

var КорневойЭлемент = System.Xml.Linq.XElement.Parse(СтрокаXML);

// Запись строки, содержащей XML в файл:

// System.IO.File.WriteAllText("ТаблицаТелефонов.xml", СтрокаXML);

// var КорневойЭлемент = System.Xml.Linq.

// XElement.Load("ТаблицаТелефонов.xml");

var Записи =

from x in КорневойЭлемент.Elements("Строка")

where (string)x.Element("Имена") == "Витя"

select x.Element("Номера_телефонов").Value;

textBox1.Text = textBox1.Text +

@"Строки, содержащие имя ""Витя"":" + "\r\n";

// Вывод коллекции записей в текстовое поле textBox1:

foreach (var x in Записи)

textBox1.Text = textBox1.Text + x + "\r\n";

// Таких записей в этой коллекции - ровно одна

}

}

}

Как видно, в начале программы мы инициализируем (т. е. присваиваем началь­ные значения) XML-строку. Далее извлекаем корневой элемент из XML-документа, он, по сути, отличается от XML-документа отсутствием XML-объявления (в этом можно убедиться в отладчике программы). В комментарии указано, как можно полу­чить корневой элемент в том случае, если он представлен в виде XML-файла во внешней памяти. Затем организуем типовой, стандартный LINQ-запрос. Результат запроса попадает в коллекцию записей, которую выводим в текстовое поле, исполь­зуя оператор цикла foreach. Фрагмент работы программы показан на рис. 19.12.

Рисунок 19.12 - LINQ-запрос к XML-документу

Убедиться в работоспособности программы можно, открыв решение Linq5.sln из папки Linq5.

5.8 LINQ-запрос к набору данных DataSet



Поделиться:


Последнее изменение этой страницы: 2016-04-26; просмотров: 647; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.12.155.100 (0.427 с.)