Раздел 10. Работа с XML файлами в Visual Studio NETАннотация: Первая глава, посвященная работе с XML
файлами, написана по материалам, собранным во время практической
работы при разборке XML файлов и их отображении в различных
документах. Вторая глава раздела посвящена вопросам,
связанным с программным формированием XML файлов. Главы 3 и 4 посвящены вопросам
хранение двоичной информации в XML файлах и созданию однопользовательских баз данных
(или собственных баз данных для приложений) на основе XML файлов без использования СУБД.
Глава 1. Доступ к содержимому XML файла в Visual Studio NET и XSLпреобразование документов
Параграф 1. Понятие XML документаXML (Extensible Markup Language) расширяемый язык разметки (на самом деле это метаязык для создания языков разметки). Язык разработан рабочей группой концерна W3C (World Wide Web Consortium) в 1996 г., стандартизован в 1998г. Он представляет собой свод общих синтаксических правил и предназначен для хранения структурированных данных и формализации обмена информацией между программами, а также для создания на его основе других специализированных языков разметки. В некотором смысле XML позволяет хранить данные аналогично файлам баз данных (в чем мы убедимся ниже). Рассмотрим реальный файла XML (один из нескольких рассылаемых Гидрометцентром в заинтересованные организации), фрагмент которого показан на Рис.1.
Рис.1 Фрагмент XML файла Обратим внимание на тот факт, что язык регистро зависим. Первая строка XML документа называется объявлением XML (declaration) это необязательная строка, указывающая версию стандарта XML. Здесь может быть указана кодировка символов и внешние зависимости. Заголовок может содержать атрибут "самодостаточности": <?xml version="1.0" standalone="no"?> Далее идут элементы документа, разделенные открывающими и закрывающими тэгами. Каждый элемент имеет имя (report, place, measurement), которым начинается открывающий тэг элемента и заканчивается закрывающий. Содержимым элемента (content), называется всё, что расположено между открывающим и закрывающим тегами. Это текст, вложенные элементы, комментарии и т.п. У элемента могут быть атрибуты - пары имя-значение, расположенные в открывающим теге после его названия. Все значения атрибутов должны быть в одинарных или двойных кавычках. Каждый XML документ обязательно содержит один корневой элемент (report) и сколько угодно вложенных элементов (place, measurement). Любой вложенный элемент также может иметь свои вложенные элементы. Комментарии вводятся конструкцией: <!-- Текст комментария --> Текстовые данные в XML называются сущностью (entity). Текст может содержать спецсимволы (некоторые символы запрещены) ссылки на сущность (entity references). Кодировка спецсимволов в XML аналогична HTML: & & < < > > ' ' " " пробел. XML поддерживает и ссылки по номеру символа (numeric character reference), тоесть любой знак может быть отображен его шестнадцатеричным представлением в Юникоде (  пробел...). Документ XML называется действительным, если он имеет связанное с ним определение типа документа (схему) и соответствует ему. В XML 1.0 единственным типом схем является DTD Document Type Definition. Однако DDT по ряду недостатков не является прямой исходной схемой XML, поэтому были разработаны различные объектные модели документов (DOM Document Object Model), которые позволяет работать с XML документом как с обычным объектом в любом современном языке программирования. Так MS XML DOM 3.0 (Microsoft), интегрирован в IE 5 и выше, MS Office 2000 и выше и MS Windows 2000 и выше. Кроме того, появились языки, позволяющие описывать внешний вид (форматирование) XML документа (XSL) и языки преобразования (стандарт XSLT XSL Transformations). В соответствии с этими стандартами и подходами в NET Framework включено несколько пространств имен и множество классов для работы с XML документами. Параграф 2. Доступ к содержимому XML файла с использованием DataSetДля доступа к данным XML применяются XML парсеры. Существует два основных типа парсеров: Document Object Model (DOM) и Simple API for XML (SAX). В первом случае документ полностью загружается в память и его структура представляется в виде дерева, что позволяет произвольно перемещаться по XML документу. SAX основан на курсорах и событиях, возникающих при проходе по узлам XML документа. Здесь документ не загружается в память, но курсор перемещается по документу только в одном направлении. Microsoft .Net Framework использует XML Document Object Model (DOM), чтобы обеспечить доступ к данным в XML документах и дополнительные классы для чтения, записи и навигации в пределах XML документа (пространства имен System.XML, System.XML.XPath, System.XML.Schema, System.XML.Serialization, System.XML.Xsl). Доступ к данным может быть организован как непосредственно выборкой из файлов (потоков), так и с использованием DataSet. Рассмотрение отображения данных с использованием DataSet, позволит нам уяснить не только структуру XML файла, но и его особенности хранения в DataSet и возможности отображения различных элементов файла. Создадим простой Web сайт, например, с именем R_XML (см. раздел "Создание Web приложений в Microsoft Visual Studio 2005") и поместим на страницу три контрола GridView и три контрола repeater (Рис.2).
Рис.2 Проект решения сайта Поместим наш фрагмент XML кода (Рис.1) в файл с именем m.xml в директорию решения, а в функции Page_Load напишем следующий код: protected void Page_Load(object sender, EventArgs e) { DataSet ds = new DataSet(); //Используем метод ReadXml DataSet загружаем файл ds.ReadXml(Server.MapPath("m.xml")); repeater1.DataSource = ds.Tables[0].DefaultView; GridView1.DataSource = ds.Tables[0].DefaultView; GridView1.DataBind(); repeater1.DataBind(); } Напомним, что данные в Repeater передаются с использованием DataBinder, а названия столбцов можно взять из отображения в GridView. <asp:Repeater id="repeater1" runat="server"> <HeaderTemplate> </HeaderTemplate> <ItemTemplate> <%# DataBinder.Eval(Container.DataItem, "code")> </ItemTemplate> </asp:Repeater> Выполним Web приложение и проанализируем результат (Рис.3)
Рис.3 Отображение корневого элемента При загрузке в GriedView из ds.Tables[0].DefaultView отображен только корневой элемент (report) и его атрибуты. Это пары имя-значение: code=1003; measured=2006/06/23 03:00; comments=Фактические данные. Причем имя атрибута стало именем столбца, а значение его содержимым. Аналогично поступил и Repeater (естественно не отображая имена столбцов, их можно самим задать в теге HeaderTemplate). Обратим внимание, что автоматически добавился еще один столбец report_Id как ключевой, который в дальнейшем можно использовать для поиска данных. Где остальное содержимое XML файла? Добавим в Page_Load еще один фрагмент кода. repiter1.DataSource = ds.Tables[1].DefaultView; GridView2.DataSource = ds.Tables[1].DefaultView; GridView2.DataBind(); repiter1.DataBind(); К таблице Рис 3. добавится таблица всех элементов первого после корневого уровня элементов с аналогичным сопоставлением атрибутов (Рис.4).
Рис.4 Отображение элементов первого уровня (place) Обратим внимание, что к единственному атрибуту code элементов второго уровня добавилось еще два столбца report_Id ключевая связь с таблицей 0 и place_Id как ID номеров code в элементах place. И последнее. Добавив код вывода из таблицы 2 DataSet, мы наконец-то доберемся до данных (содержимого элемента, content), которые нас интересуют (Рис.5). repiter3.DataSource = ds.Tables[2].DefaultView; GridView3.DataSource = ds.Tables[2].DefaultView; GridView3.DataBind(); repiter3.DataBind();
Рис.5 Отображение содержимого элементов (measurement) Здесь мы также видим place_Id. Это однозначно связывает каждую строку таблицы 2 с элементом place. Таким образом, загрузка HTML документа в DataSet выполняется, как если бы данные брались из трех (зависит от глубины вложения элементов) различных, связанных по ключам таблиц. Исходя из этого, возможно осуществлять и поиск конкретного значения данных. Это недостаточно удобно, так как требуется не только представлять структуру документа XML, но и для выполнения select по трем таблицам DataSet (может быть и более) придется знать и какие имена ID присвоит студия колонкам (правда закономерность не является сложной). Параграф 3. Пространство имен System.Xml и доступ к даннымКлассы, позволяющие .NET приложениям работать с XML документами, расположены в пространстве имен System.Xml и в дочерних пространствах имен System.Xml.Query, System.Xml.Schema, System.XmlSerialization, System.Xml.XPath и System.Xml.Xsl. Поэтому добавим в наш проект директиву: using System.Xml; Основа пространства имен XmlDocument, класс, имеющий набор свойств и методов, позволяющих отображать структуру документа и предоставлять доступ к его содержимому (DocumentElement, Schemas, ChildNodes, Attributes, FirstChild, LastChild....). Кроме того, класс имеет методы создания элементов структуры документа (CreateDocumentFragment, CreateElement, CreateNode, CreateComment ...) и методы загрузки и сохранения документа (LoadXml, Save...). Класс XmlDocument реализует W3C Document Object Model (DOM) Level 1 Core и Core DOM Level 2. XmlDocument наиболее полезен в том случае, если нужно загрузить XML документ в память для того, чтобы изменить атрибуты узлов, добавить или удалить новые элементы. DOM представляет XML документ как дерево, хранящееся в памяти, с элементом, являющимся корнем. Другие классы пространства имен XML и IO обеспечивают поддержку Xml стандартов и предоставляют интерфейс доступа к Xml документам и их трансформации (абстрактные классы XmlReader и XmlWriter обеспечивают доступ к XML данным, класс XmlNavigator предоставляет курсор навигации по XML документу, XslCompileTransform преобразовывает Xml данные, используя XSL таблицу стилей...). Рассмотрим некоторые возможности по доступу к данным с использованием System.Xml. Создадим простой Web сайт и поместим на нем контролы Button и Label. В обработчике нажатия кнопки напишем код: protected void Button1_Click(object sender, EventArgs e) { Label1.Text = ""; //Создадим XML документ XmlDocument xmldoc = new XmlDocument(); //Загрузим в документ наш xmlфайл (Рис.1) xmldoc.Load(@"C:\SamplesASP\R_XML\m.xml"); //Выполняем доступ к корневому узлу XmlNode rootnode = xmldoc.DocumentElement; //Отобразим его имя Label1.Text ="Корневой узел "+rootnode.Name+". "; //Считаем из документа все его дочерние элементы первого уровня XmlNodeList childnodes = rootnode.ChildNodes; //для каждого дочернего элемента выведем его атрибуты foreach(XmlNode node in childnodes) { Label1.Text += "Узел " + node.Name + " Объект № " + node.Attributes["code"].Value; //для каждого дочернего элемента считаем //его дочерние элементы и выведем content XmlNodeList childnodes1 = node.ChildNodes; foreach (XmlNode node1 in childnodes1) { Label1.Text += " Подузел " + node1.Name + " Облачность " + node1.Attributes["cloud"].Value + " "; } Label1.Text += "Температура "; foreach (XmlNode node1 in childnodes1) { Label1.Text += node1.Attributes["temperature"].Value + " "; } } } Для доступа к элементам можно использовать и нумерованный перебор: Label1.Text = ""; XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(@"C:\SamplesASP\R_XML\m.xml"); XmlNode rootnode = xmldoc.DocumentElement; Label1.Text = "Корневой узел " + rootnode.Name + ". "; XmlNodeList childnodes = rootnode.ChildNodes; for(int i=0; i < childnodes.Count; i++) { Label1.Text += "Узел " + childnodes[i].Name + " Объект № " + childnodes[i].Attributes["code"].Value; ........ } Результат выполнения кода показан на Рис.6.
Рис.6 XmlDocument и доступ к данным Параграф 4. XmlReader и доступ к даннымXmlReader абстрактный класс, предоставляющий последовательный (forwardonly) курсор над любыми XMLданными. Реализован как XmlTextReader, XmlNodeReader . XmlTextReaderXmlTextReader это реализация XmlReader, предоставляющая быстрый высокопроизводительный парсер. XmlTextReader требует правильно построенного XML. XmlTextReader не имеет сведений о DTD или схеме. Он только может читать текст в блоках или считывать знаки из потока. XmlTextReader имеет свойство Encoding, возвращающее кодирование знаков, найденное в атрибуте кодирования в объявлении XML. Если атрибут кодирования не найден, по умолчанию для документа устанавливается UTF8. Следующий пример показывает как можно использовать XmlTextReader для доступа к данным. XmlTextReader читает данные последовательно из потока и находит все тэги элементов, в том числе и закрывающие. Для отделения закрывающих тэгов в примере используется проверка на наличие атрибутов (HasAttributes). using System.Xml; using System.IO .... protected void Button1_Click(object sender, EventArgs e) { Label1.Text = ""; StreamReader streamreader = new StreamReader(@"C:\SamplesASP\R_XML\m.xml", //Для отображения национального шрифта System.Text.Encoding.Default); XmlTextReader xmlreader = new XmlTextReader(streamreader); //Пропускаем пустые узлы xmlreader.WhitespaceHandling = WhitespaceHandling.None; while(xmlreader.Read()) { //Читать будем только элементы if(xmlreader.NodeType == XmlNodeType.Element) { //Корневой узел if(xmlreader.Name == "report") { if(xmlreader.HasAttributes) Label1.Text += " Документ " + xmlreader.Name + " Код: " + xmlreader.GetAttribute("code") + " Дата: "+ //Можно и так, но атрибуты и так все строковые //DateTime.Parse(xmlreader.GetAttribute(1)).ToString() xmlreader.GetAttribute(1) + " Текст: " + xmlreader.GetAttribute("comments"); } //Узел первого уровня if(xmlreader.Name == "place") { if(xmlreader.HasAttributes) { Label1.Text += " Результат выполнения кода показан на Рис.7.
Рис.7 XmlTextReader и доступ к данным Иногда более удобным при доступе к информации является использование NodeType, который позволяет выделить из документа не только элементы, но и объявление (XmlNodeType.XmlDeclaration), коментарии (XmlNodeType.Comment), просто текст между элементами (XmlNodeType.Text) и символы пробелов и табуляции (XmlNodeType.SignificantWhitespace), конечные тэги элементов (XmlNodeType.EndElement), текст, заключенный в тэги <? ?> (XmlNodeType.ProcessingInstruction). В этом случае целесообразно использовать оператор switch: switch(xmlreader.NodeType) { //Можно достать все из объявления XML case XmlNodeType.XmlDeclaration: Label1.Text = xmlreader.Name + " Версия: " + xmlreader.GetAttribute("version"); break; //Если есть текст между элементами, то его можно вывести case XmlNodeType.Text: case XmlNodeType.SignificantWhitespace: Label1.Text += " XmlNodeReaderПредоставляет средство чтения, обеспечивающее быстрый прямой доступ (без кэширования) к данным XML класса XmlDocument. Свойства и методы его аналогичны XmlTextReader и, поэтому, здесь не будем останавливаться подробно на примере доступа к данным, так как после выполнения кода загрузки далее можно без изменений использовать предыдущий код: Label1.Text = ""; XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(@"C:\SamplesASP\R_XML\m.xml"); //Создание XmlNodeReader на базе XmlDocument XmlNodeReader xmlreader = new XmlNodeReader(xmldoc); ..... Параграф 5. XPath и доступ к даннымXPath язык запросов к элементам структуры XML документа. Пространство имен System.Xml.XPath содержит парсер XPath и механизм проверки данных. Модель данных XPath предоставляет методы, необходимые для реализации запросов XPath к любому хранилищу данных. Это методы Select, Evaluate класса XPathNavigator и итератор для навигации по узлам документа (XPathNodeIterator). Класс XPathDocument предоставляет быстрый доступ, доступный только для чтения кэш для процесса обработки документа, использующего XSLT. Кроме того, пространство имен имеет и классы обработки прерываний. Для демонстрации некоторых возможностей XPath слегка изменим наш xml файл (да простит нас Гидрометцентр!): <?xml version="1.0" encoding="windows1251"?> <report code="1003" measured="2006/06/23 03:00" comments="Фактические данные"> <coments> Прогноз погоды по городам </coments> <place code="91"> <city>Питер</city> <measurement cloud="0" rain="1000" /> <temperature>22.7</temperature> </place> <place code="92"> <city>Петрозаводск</city> <measurement cloud="1" rain="1000" /> <temperature>21.7</temperature> </place> <place code="93"> <city>Сортавала</city> <measurement cloud="0" rain="1000" /> <temperature>19</temperature> </place> </report> Следующий код демонстрирует основные возможности доступа к данным: using System.Xml; using System.Xml.XPath; using System.IO; ....... protected void Button1_Click(object sender, EventArgs e) { Label1.Text = ""; //Создаем XPathDocument XPathDocument xpdocument = new XPathDocument(@"C:\SamplesASP\R_XML\k.xml"); //XPathNavigator реализует интерфейс IXPathNavigable XPathNavigator xpnavigator = ((IXPathNavigable)xpdocument).CreateNavigator(); //Выражение для поиска XPathExpression xPathExpression = xpnavigator.Compile("report/place"); //XPathNodeIterator будет содержать все узлы place XPathNodeIterator xpiterator = xpnavigator.Select(xPathExpression); //Хотя можно и так //XPathNodeIterator xpiterator = xpnavigator.Select("report/place"); while(xpiterator.MoveNext()) { //Так как после любого сдвига первоначальное InnerXml теряется, //то создаем 3 XPathNodeIterator для дочерних узлов XPathNodeIterator xpiterator2 = xpiterator.Current.SelectChildren("report/place", ""); //Можно и так, но будет разница в обработке XPathNodeIterator xpiterator3 = xpiterator.Current.SelectChildren("temperature", ""); XPathNodeIterator xpiterator1 = xpiterator.Current.SelectChildren("measurement", ""); //Выбор атрибута из узла place xpiterator.Current.MoveToAttribute("code", ""); Label1.Text += "
Рис.8 XPath и доступ к данным Отметим несколько моментов, связанных с методом Select:
Следующий пример приведен здесь, чтобы мы могли уяснить не только механизм селективной выборки данных, но и где она осуществляется и как хранятся данные. protected void Button3_Click(object sender, EventArgs e) { Label1.Text = ""; //Можно так загрузить для возможности отображения //национального шрифта //StreamReader streamreader = // new StreamReader(@"C:\SamplesASP\R_XML\k.xml", // System.Text.Encoding.Default); //XPathDocument xpdocument = new XPathDocument(streamreader); //А можно позволить XPathDocument извлечь кодировку из declaration XPathDocument xpdocument = new XPathDocument(@"C:\SamplesASP\R_XML\k.xml"); XPathNavigator xpnavigator = xpdocument.CreateNavigator(); //Проведем ограниченную выборку XPathNodeIterator xpiterator = xpnavigator.Select("report/place[2] | report/place[3]"); //Демонстрируем, что XPathNodeIterato хранит в Current полный // документ, независимо оттого, что проведен Select //Преобразуем тэг < для возможности отображения на странице HTML Label1.Text += " Результаты выполнения кода показаны на Рис.9.
Рис.9 XPath и доступ к данным Из примера видно, что XPathNodeIterator всегда переносит данные в свой класс, а селекция выполняется уже в данном классе, причем только после выполнения MoveNext(). Для более глубокого изучения процессов выборки данных можно в режиме пошагового выполнения добавить xpiterator в QuickWatch и просмотреть последовательность смены свойств при выполнении MoveNext(). Параграф 6. XSLпреобразование документаExtensible Stylesheet Language (XSL расширяемый язык таблиц стилей) - язык для преобразования XMLданных. Преобразования XSLT (XSL Transform) позволяет подготовить данные в XML файлах, а затем преобразовать этот файл в различные форматы документов (txt, html, xls... ). XSLT вместе с CSS позволяют форматировать Web сайты. В этом случае он содержит шаблон HTML страницы. В случае, когда XSLT приводится к словарю форматирования XSL, данное преобразование выполняет функции стиля (stylesheet). XSL файл - это, по сути, описание правил преобразования исходного дерева документа в конечное дерево. Преобразование строится путем сопоставления образцов и шаблонов. Образец сравнивается с элементами исходного дерева, а шаблон используется для создания частей конечного дерева. Конечное дерево отделено от исходного дерева. Структура конечного дерева может полностью отличаться от структуры исходного дерева. XSL не конкретизирует, каким образом стиль XSLT привязывается к документу XML. Необходимым является поддержка механизма XSL в языке обработки данных. XSL преобразования могут применяться и для преобразования XML документов в XML документы с другим форматом. Такая необходимость может возникнуть при передаче информации между разными информационными системами или организациями, использующими различные типы описания одной и той же информации, национальные языки и т.п. В задачу этого материала не входит рассмотрение языка XSL. Для более глубокого понимания материала можно обратиться к книге: "Язык преобразований XSL (XSLT) Версия 1.0 Рекомендация W3C от 16 ноября 1999": английская версия http://www.w3.org/TR/1999/REC-xslt-19991116 или перевод Рудика Усманова http://www.rol.ru/news/it/helpdesk/xslt01.htm или http://www.w3.org/TR/1999/REC-xslt-19991116 Последующий материал посвящен практическому применению преобразований, где, в процессе рассмотрения примеров, мы будем касаться структуры XSL файлов. Все примеры параграфа будем рассматривать с использованием нашего XML файла ("слегка измененного файла рассылки Гидрометцентра"). В начале выведем его в браузере как HTML файл, затем как страничку Excel и Word. 6.1 XML >> HTMLВ любом проекте (можно в предыдущем), изменим код нажатия кнопки и внесем некоторые другие изменения, с тем, чтобы вывести наш XML файл как Web страницу, показанную на Рис.10.
Рис.10 Использование XSL Код нажатия кнопки using System.Data.SqlClient; using System.Xml; using System.Xml.Xsl; using System.Xml.XPath; using System.IO; ...... protected void Button1_Click(object sender, EventArgs e) { //Используем StreamReader для возможности отображения //национального шрифта и загружаем в него наш файл StreamReader streamreader = new StreamReader(@"C:\SamplesASP\R_XML\k.xml", System.Text.Encoding.Default); //Определяем, что вывод будет в HTML Response.ContentType = "text/html"; Response.Charset = "windows1251"; //DataSet необходим для структурированного хранения //документа и создания класса для преобразования //XmlDataDocument. Кроме того, это подсказывает //что аналогично можно отображать и данные из //БД, выполнив над таблицами необходимый Select DataSet ds = new DataSet(); //Или можно и так, когда нет проблем с кодировкой //ds.ReadXml(@"C:\SamplesASP\R_XML\k.xml"); ds.ReadXml(streamreader); //Создаем XmlDataDocument XmlDataDocument xdd = new XmlDataDocument(ds); //Создаем класс для преобразования XslCompiledTransform XslCompiledTransform xt = new XslCompiledTransform(); //Загружаем в него шаблон стилей //Его чуть подробнее рассмотрим ниже xt.Load(Server.MapPath("template1.xslt")); //Преобразуем документ по шаблону и выводим результат xt.Transform(xdd, null, Response.OutputStream); Response.Flush(); Response.Close(); streamreader.Close(); } После выполнения кода получим результат, показанный на Рис.10., но при одном условии наличии файла шаблона template1.xslt. Создание файла шаблона может показаться слегка усложненной задачей, если не рассматривать его как структурированный документ. Вначале (синий цвет) идут обязательные объявления для данного преобразования. Их просто переносим в свой файл отсюда или берем из документа, созданного мастером (контекстное меню решения, Add New Item, выбираем XSLTFile, задаем имя и можем, если очень хочется, чуть-чуть изменить и расширение на xslt). В созданном мастером файле практически более ничего и нет, кроме выделенного синим цветом и заготовки начала и конца документа. Но есть главное:
Далее (темно зеленый цвет), то, как мы структурируем документ и как его хотим раскрасить (обычное для HTML документов head, body, table), необычно лишь то, что они действуют в пределах тэга <xsl:template match="/"> , что можно трактовать как - относится к заголовку. Стили элементов обычный язык CSS(Cascading Style Sheets) . Далее (темно красный цвет) - заголовок документа или то, что мы могли взять из корневого элемента XML файла (при наличии в корневом элементе атрибутов расшифровки содержимого XML файла). В данном примере XML файла этого нет, и мы формируем заголовок таблицы как в обычном HTML файле. Осталось несколько строчек, то, что участвует в преобразовании и выводится из XML файла. Тэг xsl:foreach говорит, что мы встали на уровень элементов place нашего документа XML и нам доступно все, что есть в элементе place и вложенных в него элементах (в том числе и аргументы). <xsl:foreach select="//place"> <?xml version="1.0" encoding="windows1251"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <head> <Style ID="Default" Name="Normal"> body{fontfamily : Arial, Helvetica,sansserif;fontsize:11pt; BACKGROUNDCOLOR: "#ffffcc"; COLOR : "navy"} table{border: 1px solid red; bordercollapse:separate; backgroundcolor:"#000000";} th {fontfamily:arial; fontsize:14pt; backgroundcolor:"#F8F0FF";color:darkred;} td {fontfamily:arial; fontsize:14pt; backgroundcolor:"#F0F8FF";color:black;} p{color : black; align : left; fontsize : 14pt;textindent:20pt;} </Style> <html> <body> <p>Пример XML >> HTML</p> <table> <tr> <th> Город</th> <th> Код города</th> <th> Температура</th> </tr> <!-- Применяем ко всем элементам Place --> <xsl:foreach select="//place"> <tr> <td> <xsl:valueof select="city"/> </td> <td> <!-- выборка аргумента --> <xsl:valueof select="@code" /> </td> <td> <xsl:valueof select="temperature" /> </td> </tr> </xsl:foreach> <!-- Применяем ко всем элементам в report - он один - значит все повторим один раз --> <xsl:foreach select="//report"> <tr> <td colspan="2">Средняя температура по региону: </td> <td> <xsl:valueof select="(sum(place/temperature)) *(count(place/temperature)*0.1)" /> </td> </tr> </xsl:foreach> </table> </body> </html> </head> </xsl:template> </xsl:stylesheet> Еще несколько моментов. Так достаются значения контента оператором select: //Для текста <xsl:valueof select="city"/> //Для аргументов <xsl:valueof select="@code" /> //Опять для текста <xsl:valueof select="temperature" /> И последняя конструкция, расчет средней температуры по региону. Мы поднимаемся чуть выше в документе, чтобы были доступны все элементы temperature по пути place/temperature и не мешались остальные элементы. <!-- Применяем ко всем элементам в report --> <xsl:foreach select="//report"> Выполняем и выводим расчет: <xsl:valueof select="(sum(place/temperature)) *(count(place/temperature)*0.1)" /> Осталось закрыть все открытые тэги и использовать шаблон не только в этой программе, но и в других. И выполнить решение (Рис.10). Еще один - упрощенный пример использования преобразования, которое может быть часто востребовано на практике, показано на Рис.11. Заменив в программе шаблон и XML файл, на приведенные ниже, мы можем легко формировать вывод не только простых XML, но и данных из таблиц БД.
Рис.11 Использование XSL Файл XML: <weather> <city id="95"> <name>Мурманск</name> <temperature point="10.00">11</temperature> <temperature point="20.00">12</temperature> </city> <city id="93"> <name>Петрозаводск</name> <temperature point="10.00">14</temperature> <temperature point="20.00">15</temperature> </city> </weather> Файл template: <?xml version="1.0" encoding="windows-1251"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <head> <title>Погода</title> </head> <body> <table border="1"> <xsl:for-each select="//weather"> <tr> <th rowspan="2">< font color="red">Город</font> </th> <th> Время/Температура </th> <th> Время/Температура </th> </tr><tr> <!-- Чтобы брать только из одного элемента - city[1] --> <xsl:for-each select="/weather/city[1]/temperature"> <th align="center"> <xsl:apply-templates select ="@point"/> </th> </xsl:for-each> </tr> </xsl:for-each> <-- Для всех узлов city --> <xsl:for-each select="//city"> <tr> <th> <xsl:apply-templates select="name"/> </th> <xsl:for-each select="temperature"> <td align="center"> <xsl:apply-templates/> </td> </xsl:for-each> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> 6.2 XML >> XMLИзменим одну строчку кода и можем посмотреть в браузере как выглядит преобразованный по template xml документ. Response.ContentType = "text/xml"; Здесь практически мы наблюдаем HTML файл, преобразованный к виду XML. Его можно скопировать в файл с расширением .html (изменив или убрав первую строку) и это готовый статичный документ HTML. <?xml version="1.0" encoding="utf8" ?> <head> <Style ID="Default" Name="Normal" >body{fontfamily : Arial, Helvetica, sansserif;fontsize:11pt; BACKGROUNDCOLOR: "#ffffcc"; COLOR : "navy"} table{border: 1px solid red; bordercollapse:separate; backgroundcolor:"#000000";} th {fontfamily:arial; fontsize:14pt; backgroundcolor:"#F8F0FF";color:darkred;} td {fontfamily:arial; fontsize:14pt; backgroundcolor:"#F0F8FF";color:black;} p{color : black; align : left; fontsize : 14pt;textindent:20pt;}</Style> <html> <body> <p>Пример XML >> HTML</p> <table> <tr> <th>Город</th> <th>Код города</th> <th>Температура</th> </tr> <tr> <td>Питер</td> <td>91</td> <td>22.7</td> </tr> <tr> <td>Петрозаводск</td> <td>92</td> <td>21.7</td> </tr> <tr> <td>Сортавала</td> <td>93</td> <td>19</td> </tr> <tr> <td colspan="2">Средняя температура по региону:</td> <td>19.020000000000003</td> </tr> </table> </body> </html> </head> 6.3 XML >> ExcelВновь, как и в п. 6.1, рассмотрим сначала результат, который мы хотим получить, показанный на Рис.12. Это Web страничка, в которую внедрена Excel таблица с данными XML файла.
Рис.12 Использование XSL Программный код, за исключением 1й строки и смены файла template, аналогичен коду п. 6.1: protected void Button1_Click(object sender, EventArgs e) { StreamReader streamreader = new StreamReader(@"C:\SamplesASP\R_XML\m1.xml", //Для отображения национального шрифта System.Text.Encoding.Default); Response.ContentType = "application/vnd.ms-excel"; Response.Charset = "windows-1251"; DataSet ds = new DataSet(); ds.ReadXml(streamreader); //Но можно и так Response.Charset = "windows-1251"; установит кодировку //ds.ReadXml(@"C:\SamplesASP\R_XML\m1.xml"); XmlDataDocument xdd = new XmlDataDocument(ds); XslCompiledTransform xt = new XslCompiledTransform(); xt.Load(Server.MapPath("template2.xslt")); xt.Transform(xdd, null, Response.OutputStream); Response.Flush(); Response.Close(); streamreader.Close(); } Эти два изменения и отображают точки редактирования различных преобразований. Основа - файл template, содержимое которого может показаться кошмарным. Но, при структурированном рассмотрении (как мы делали это в п. 6.1), выяснится, что он не сложнее предыдущего. Ниже мы покажем, что шаблон может делать и сам Excel. А пока рассмотрим составляющие структуры:
<?xml version="1.0" encoding = "windows-1251" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"> <xsl:template match="/"> <xsl:processing-instruction name="mso-application"> <xsl:text>progid="Excel.Sheet" </xsl:text> </xsl:processing-instruction> <Workbook> <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"> <Author>Wlad Moltchanov</Author> <Created>2006-07-07</Created> <Version>1.0</Version> </DocumentProperties> <Styles> <Style ss:ID="Default" ss:Name="Normal"> <Alignment ss:Vertical="Bottom" /> <Borders/> <Font ss:Size="12" ss:FontName="Arial" x:Family="Roman" ss:Bold="1"/> <Interior/> <NumberFormat /> <Protection /> </Style> <Style ss:ID="F1"> <Alignment ss:Vertical="Center" /> <Borders> <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="2"/> <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="2"/> <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="2"/> <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="2"/> </Borders> <Font ss:Size="14" ss:FontName="Arial"/> <Interior ss:Color="#FFCC99" ss:Pattern="Solid"/> <NumberFormat /> <Protection /> </Style> <Style ss:ID="F2"> <Alignment ss:Vertical="Center" /> <Borders> <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/> </Borders> <Font ss:Size="14" ss:FontName="Arial"/> <Interior ss:Color="#FF99CC" ss:Pattern="Solid"/> <NumberFormat ss:Format="_-* #,##0.00\ "_"_-;\-* #,##0.00\ "_"_-;_-* "-"??\ "_"_-;_-@_-"/> <Protection /> </Style> </Styles> <Worksheet ss:Name="Лист 1"> <!-- Имя Листа Документа --> <Table> <Row> <Cell ss:StyleID="F1"> <Data ss:Type="String">Город</Data> </Cell> <Cell ss:StyleID="F1"> <Data ss:Type="String">Код</Data> </Cell> <Cell ss:StyleID="F1"> <Data ss:Type="String">Температура</Data> </Cell> <Cell ss:StyleID="F1"> <Data ss:Type="String">Облачность</Data> </Cell> </Row> <xsl:apply-templates select="//place" /> <Row> <Cell> <Data ss:Type="String">Средняя температура по региону:</Data> </Cell> <Cell> </Cell> <Cell> <!-- R строка текущая - навигация [+X] [-X] C - столбец текущий - навигация [+X] [-X] Менять местами нельзя --> <xsl:attribute name="ss:Formula">=((R[-<xsl:value-of select="count(NewDataSet/report/place/temperature)"> <!-- Или так select="count(//report/place/temperature)"--> </xsl:value-of>]C+R[-1]C)/3)</xsl:attribute> </Cell> </Row> </Table> </Worksheet> </Workbook> </xsl:template> <xsl:template match="place"> <Row> <Cell ss:StyleID="F2"> <Data ss:Type="String"> <xsl:value-of select="city" /> </Data> </Cell> <Cell ss:StyleID="F2"> <Data ss:Type="String"> <xsl:value-of select="@code" /> </Data> </Cell> <Cell ss:StyleID="F2"> <Data ss:Type="String"> <xsl:value-of select="temperature" /> </Data> </Cell> <Cell ss:StyleID="F2"> <Data ss:Type="String"> <xsl:value-of select="measurement/@cloud" /> </Data> </Cell> </Row> </xsl:template> </xsl:stylesheet> Но есть способ проще: Откроем Excel 2003 и наберем в новом файле информацию, структурно схожую с той, которую нам необходимо вывести (для таблицы, например, заголовок и одну строку и т.п.). Сохраним файл как таблицу XML. Очень громоздкий текстовый файл будет содержать все тэги, все форматирование, стили и т.п. и много-много чего лишнего. Останется только убрать лишнее и наложить xsl тэги на параметры полученного файла. 6.4 XML >> WordВнесем минимальные изменения в коде обработчика нажатия кнопки: Response.AddHeader("Content-Disposition", "attachment; filename=my.xml;"); Response.ContentType = "application/msword"; Вновь используем файл XML: <weather> <city id="95"> <name>Мурманск</name> <temperature point="10.00">11</temperature> <temperature point="20.00">12</temperature> </city> <city id="93"> <name>Петрозаводск</name> <temperature point="10.00">14</temperature> <temperature point="20.00">15</temperature> </city> </weather> И код файла xslt (в котором мы учли, что Word может отображать web страницы): <xsl:stylesheet version="1.0" <!-- Можно убрать все лишнее --> xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" > <xsl:template match="/"> <html> <head> </head> <body> <table border="1"> <xsl:for-each select="//weather"> <tr> <th rowspan="2"> <font color="red">Город</font> </th> <th> Время/Температура </th> <th> Время/Температура </th> </tr> <tr> <xsl:for-each select="/weather/city[1]/temperature"> <th align="center"> <xsl:apply-templates select ="@point"/> </th> </xsl:for-each> </tr> </xsl:for-each> <xsl:for-each select="//city"> <tr> <th> <xsl:apply-templates select="name"/> </th> <xsl:for-each select="temperature"> <td align="center"> <xsl:apply-templates/> </td> </xsl:for-each> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> Результат выполнения кода показан на Рис.13.
Рис.13 Использование XSL Еще одна возможность XSL быстро сменить форму вывода документа - это использование директивы пространства имен xsl output method (может иметь значения html, text, xml): .................. <xsl:output method="xml" media-type="application/msword" /> <xsl:template match="/"> ........... output method может содержать и другие параметры, например: <xsl:output method="html" version="3.0" doctype-public="-//IEFT//DTD HTML//EN" media-type="application/msword" encoding="windows-1251"/> Результат выполнения кода показан на Рис.14.
Рис.14 Использование XSL В предыдущем примере мы создали шаблон, пригодный только для отображения. Если же нам требуется сформировать XML файл, который можно будет далее использовать, то потребуется применение правильного XML форматирование для Word. В этом случае template для нашего примера будет выглядеть примерно так (код обработчика кнопки не изменится): <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- <xsl:output method="html" media-type="application/msword"/> --> <xsl:template match="/"> <w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml"> <w:styles> <w:style w:type="paragraph" w:styleId="S1" w:default="on"> <w:pPr> <w:jc w:val="center"/> <w:b w:val="off" /> </w:pPr> <w:rPr> <w:i w:val="on"/> <w:b w:val="on"/> <w:jc w:val="center"/> <w:color w:val="00FF00"/> <w:rFonts w:ascii="Arial" w:h-ansi="Arial" w:cs="Arial"/> </w:rPr> </w:style> </w:styles> <w:styles> <w:style w:type="character" w:styleId="S2" w:default="off"> <w:name w:val="S2"/> <w:basedOn w:val="Normal"/> <w:next w:val="Normal"/> <w:rPr> <w:i w:val="on"/> <w:b w:val="on"/> <w:jc w:val="left"/> <w:color w:val="FFFFFF"/> <w:rFonts w:ascii="Arial" w:h-ansi="Arial" w:cs="Arial"/> <w:kern w:val="24"/> <w:sz w:val="24"/> </w:rPr> </w:style> <w:style w:type="character" w:styleId="S3" w:default="off"> <w:name w:val="S3"/> <w:basedOn w:val="Normal"/> <w:next w:val="Normal"/> <w:rPr> <w:color w:val="000000"/> </w:rPr> </w:style> </w:styles> <w:body> <w:tbl> <w:tr> <w:trPr> <w:gridSpan w:val="2" /> </w:trPr> <w:tc> <w:tcPr> <w:shd w:fill="FF0000"/> </w:tcPr> <w:p> <w:r> <w:rPr> <w:rStyle w:val="S2"/> <w:t> Город </w:t> </w:rPr> </w:r> </w:p> </w:tc> <w:tc> <w:tcPr> <w:gridSpan w:val="2" /> </w:tcPr> <w:p> <w:r> <w:rPr> <w:b w:val="on" /> <w:t> Время/Температура </w:t> </w:rPr> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:p> <w:r> <w:t> </w:t> </w:r> </w:p> </w:tc> <xsl:for-each select="/weather/city[1]/temperature"> <w:tc> <w:p> <w:r> <w:t> <xsl:apply-templates select ="@point"/> </w:t> </w:r> </w:p> </w:tc> </xsl:for-each> </w:tr> <xsl:for-each select="//city"> <w:tr> <w:tc> <w:p> <w:r> <w:t> <xsl:apply-templates select="name"/> </w:t> </w:r> </w:p> </w:tc> <xsl:for-each select="temperature"> <w:tc> <w:p> <w:r> <w:rPr> <w:rStyle w:val="S3"/> </w:rPr> <w:t> <xsl:apply-templates/> </w:t> </w:r> </w:p> </w:tc> </xsl:for-each> </w:tr> </xsl:for-each> </w:tbl> </w:body> </w:wordDocument> </xsl:template> </xsl:stylesheet>
Рис.15 Использование XSL Если кто хочет подробно изучить XML в среде Microsoft Word 2003 можно обратитя к первоисточникам (MSDN. Word 2003 Template или MSDN. XSL Transform) или найти другую литературу. Но опять, как и для Excel, есть способ проще: Откроем Word 2003 и наберем в новом файле информацию, структурно схожую с той, которую нам необходимо вывести (для таблицы, например, заголовок и одну строку и т.п.). Сохраним файл как XML документ. Очень громоздкий текстовый файл будет содержать все тэги, все форматирование, стили и т.п. и много-много чего лишнего. Останется только убрать лишнее и наложить xsl тэги на параметры полученного файла. Литература:Молчанов Владислав 11.07.2006г. Еcли Вы пришли с поискового сервера - посетите мою главную страничкуНа главной странице Вы найдете программы комплекса Veles - программы для автолюбителей,
программу NumberPhoto, созданную для работы с фото, сделанными цифровым фотоаппаратом,
программу Локальный Web сайт - предназначенную для просмотра и прослушивания
файлов большинства графических и звуковых форматов в Web Browser,
программу Bricks - игрушку для детей и взрослых, программу записную книжку,
программу TellMe - говорящий Русско-Английский разговорник - программу для тех, кто собирается
погостить за бугром или повысить свои знания в английском, теоретический материал
по программированию в среде Borland C++ builder, C# (Windows приложения и ASP.Net Web сайты).
|