? Доступ к содержимому XML файла в Visual Studio 2005

В начало книги

Раздел 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.

xml0001.gif

Рис.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:

 
&amp; &
&lt   <
&gt;  > 
&apos; '
&quot; "
&nbsp; пробел.

XML поддерживает и ссылки по номеру символа (numeric character reference), тоесть любой знак может быть отображен его шестнадцатеричным представлением в Юникоде (&#160; пробел...).

Документ 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).

xml0002.gif

Рис.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)

xml0003.gif

Рис.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).

xml0004.gif

Рис.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();     

xml0005.gif

Рис.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.

xml0006.gif

Рис.6 XmlDocument и доступ к данным


В начало

Параграф 4. XmlReader и доступ к данным

XmlReader абстрактный класс, предоставляющий последовательный (forwardonly) курсор над любыми XMLданными. Реализован как XmlTextReader, XmlNodeReader .

XmlTextReader

XmlTextReader это реализация 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 += "
Узел " + xmlreader.Name; for(int i = 0; i < xmlreader.AttributeCount; i++) { Label1.Text += " Объект № " + xmlreader.GetAttribute(i); } } } // //Узел сущности if(xmlreader.Name == "measurement") { if(xmlreader.HasAttributes) { for(int i = 0; i < xmlreader.AttributeCount; i++) { Label1.Text +=" Атрибут № " +Convert.ToString(i)+" равен "+ xmlreader.GetAttribute(i); } } } }//if(xmlreader.NodeType == XmlNodeType.Element) }//while(xmlreader.Read()) }

Результат выполнения кода показан на Рис.7.

xml0007.gif

Рис.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 += "
" + xmlreader.Value; break; ......... }

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 += " 
Код " + xpiterator.Current.Value; //И выбор дочерних узлов xpiterator2.Current.MoveToChild("city", ""); Label1.Text += " Город " + xpiterator2.Current.Value; //При Select непосредственно узла нет необходимости перехода к узлу //xpiterator3.Current.MoveToChild("temperature", ""); //но встать на выбранный узел надо xpiterator3.MoveNext(); Label1.Text += " Температура " + xpiterator3.Current.Value; while(xpiterator1.MoveNext()) { xpiterator1.Current.MoveToAttribute("cloud", ""); Label1.Text += " Облачность " + xpiterator1.Current.Value; } } //Прямой доступ к элементам без обхода дерева Label1.Text += "
Средняя температура по региону " + xpnavigator.Evaluate("sum(report/place/temperature)div 3"); }

xml0008.gif

Рис.8 XPath и доступ к данным

Отметим несколько моментов, связанных с методом Select:

  • для идентификации элемента во всех местах документа используется два слеша в начале выражения:

  • для указания элементов пути, имена которых неизвестны, либо нет желания их писать, можно воспользоваться символом *.

  • Для фильтрации элементов документа нужно использовать предикаты выражения, заключенные в квадратные скобки. В предикатах могут участвовать атрибуты тегов и значения вложенных тегов. При этом, перед атрибутами тегов, участвующих в фильтрации, ставиться амперсанд @, а перед вложенными тегами нет. Предикаты можно объединять ключевыми словами or и and.

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

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 += "

" + xpiterator.Current.Value; string s = xpiterator.Current.InnerXml; while (s.IndexOf("<") != 1) s = s.Substring(0, s.IndexOf("<")) + "<" +s.Substring(s.IndexOf("<") + 1,s.Length s.IndexOf("<")1); //И отобразим Рис 9 (a). Label1.Text += "
 " + s + "
"; //А теперь посмотрим, как выполняется выбор while (xpiterator.MoveNext()) { s = xpiterator.Current.InnerXml; while (s.IndexOf("<") != 1) s = s.Substring(0, s.IndexOf("<")) + "<" + s.Substring(s.IndexOf("<") + 1, s.Length s.IndexOf("<") 1); //Это все, что есть в Current на данном шаге Рис 9 (b). Label1.Text += "

" + xpiterator.Current.Value; //А это то, что есть Current.InnerXml Рис 9 (b). Label1.Text += "
 " + s + "
"; } }

Результаты выполнения кода показаны на Рис.9.

xml0009.gif

Рис.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.

xml0010.gif

Рис.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). В созданном мастером файле практически более ничего и нет, кроме выделенного синим цветом и заготовки начала и конца документа. Но есть главное:

  • 1. Собственно начало файла стиля (xsl:stylesheet или синоним xsl:transform). Элемент xsl:stylesheet обязан иметь атрибут version, указывающий какая версия XSLT необходима для этого стиля. Элемент xsl:stylesheet может содержать в качестве параметров различные типы элементов, которые различны в разных преобразованиях. Если название элемента имеет префикс, то этот префикс преобразуется в ссылку URI с помощью деклараций пространства имен в xsl:stylesheet.

  • 2. Пространство имен XSLT, задано как URI http://www.w3.org/1999/XSL/Transform. Чтобы идентифицировать элементы и атрибуты из указанного пространства, XSLT процессоры должны использовать механизмы указанного пространства имен. Для обращения к элементам из пространства имен XSLT в данной спецификации использует префикс xsl:.

  • 3. Граница начала применения template - атрибут match. <xsl:template match="/"> означает, что это относится к корневому элементу. Атрибут match идентифицирует узлы, к которым применяется правило стиля. Помним, что DataSet добавит свой корневой элемент NewDataSet. Построение результирующего дерева всегда начинается с корневого узла.

Далее (темно зеленый цвет), то, как мы структурируем документ и как его хотим раскрасить (обычное для 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, но и данных из таблиц БД.

xml0011.gif

Рис.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 файла.

xml0012.gif

Рис.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. А пока рассмотрим составляющие структуры:

  • Обязательные объявления для данного преобразования (синий цвет) (их просто переносим в свой файл из любого аналогичного шаблона).
       Более подробно о пространствах имен можно посмотреть MSDN. XML in Excel and the Spreadsheet Component и MSDN. XML Spreadsheet Reference. Обратим внимание на элемен template - тэг <xsl:template match="/"> - отнести к корневому элементу.

  • Определение стилей (темно зеленый цвет). В примере определены два стиля, содержимое тэгов которых близко к знакомым нам макросам из VBA Excel. Префикс ss определен выше, как ссылка на схему, созданную разработчиками: (<xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">);

  • Далее определяется содержимое листа и заголовка таблицы Excel (темно красный цвет).

  • И, наконец, собственно использование template для преобразования и вывода данных (темно синий цвет тэг <xsl:apply-templates select="//place" />).

    Тэг xsl:apply-templates (как и ранее использованный нами xsl:foreach) говорит, что мы встали на уровень элементов place нашего документа XML и нам доступно все, что есть в элементе place и вложенных в него элементах (в том числе и аргументы), а последующий код применим ко всем элементам place. Кроме того, с этой строки закончилась часть документа, которая определяет заглавие таблицы.

    <xsl:apply-templates select="//place" />
    
<?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.

xml0013.gif

Рис.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.

xml0014.gif

Рис.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>

xml0015.gif

Рис.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 сайты).

В начало страницы и раздела

В начало книги

На главную страницу сайта


Сайт управляется системой uCoz