<booktitle>The Great Cookie Caper</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
<discbook>
<booktitle>A Really Great Book</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
</books>
Определим новый класс BookUtils. В этом классе мы имеем один практически бесполезный метод, который возвращает строку "This came from the ShowText method!". Для события button1_Click создаются XPathDocument и XslTransform так же, как это делалось раньше, но с некоторыми исключениями. В этот раз мы собираемся создать документ XML, поэтому используем XMLWriter вместо FileStream. Вот эти изменения:
XsltArgumentList argBook=new XsltArgumentList();
BookUtils bu=new BookUtils();
argBook.AddExtensionObject("urn:ProCSharp", bu);
Именно здесь создается XsltArgumentList. Мы создаем экземпляр объекта BookUtils, и когда вызывается метод AddExtensionObject, ему передается пространство имен расширения и объект, из которого мы хотим вызывать методы. Когда делается вызов Transform, ему передаются XsltArgumentList (argBook) вместе с XPathNavigator и созданный объект XmlWriter. Вот документ booksarg.xsl:
<xsname = "note" stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:bookutil="urn:ProCSharp">
<xsname = "note" output method="xml" indent="yes"/>
<xsname = "note" template match="/">
<xsname = "note" element name="books">
<xsname = "note" apply-templates/>
</xsname = "note" element>
</xsname = "note" template>
<xsname = "note" template match="bookstore">
<xsname = "note" apply-templates select="book"/>
</xsname = "note" template>
<xsname = "note" template match="book">
<xsname = "note" element name="discbook">
<xsname = "note" element name="booktitle">
<xsname = "note" value-of select="title"/>
</xsname = "note" element>
<xsname = "note" element name="showtext">
<xsname = "note" value-of select="bookUtiname = "note" ShowText()"/>
</xsname = "note" element>
</xsname = "note" element>
</xsname = "note" template>
</xsname = "note" stylesheet>
Здесь имеются две важные строки. В начале добавляется пространство имен, которое создается при добавлении объекта к XsltArgumentList. Затем применяется стандартный синтаксис использования префикса перед пространством имен XSLT и вызывается метод.
Иначе это можно было бы выполнить с помощью сценария XSLT. В таблицу стилей можно включить код C#, VB и JavaScript. Большим достоинством этого является то, что в отличие от текущих реализаций, сценарий компилируется при вызове Transform.Load; таким образом выполняются уже откомпилированные сценарии, в значительной степени так же, как работает ASP.NET. Давайте выполним предыдущий пример таким способом. Добавим сценарий к таблице стилей. Эти изменения можно увидеть в файле bookscript.xsl:
<xsname = "note" stylesheet version="1.0" xmlns:Xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user="http://wrox.com">
<msxsname = "note" script language="C#" implements-prefix="user">
string ShowText() {
return "This came from the ShowText method!";
}
</msxsname = "note" script>
<xsname = "note" output method="xml" indent="yes"/>
<xsname = "note" template match="/">
<xsname = "note" element name="books">
<xsname = "note" apply-templates/>
</xsname = "note" element>
</xsname = "note" template>
<xsname = "note" template match="bookstore">
<xsname = "note" apply-templates select="book"/>
</xsname = "note" template>
<xsname = "note" template match="book">
<xsname = "note" element name="discbook">
<xsname = "note" element name="booktitle">
<xsname = "note" value-of select="title"/>
</xsname = "note" element>
<xsname = "note" element name="showtext">
<xsname = "note" value-of select="user:ShowText()"/>
</xsname = "note" element>
</xsname = "note" element>
</xsname = "note" template>
</xsname = "note" stylesheet>
Изменения включают задание пространства имен сценариев, добавление кода (который скопирован из VS.NET IDE) и выполнение вызова в таблице стилей. Вывод выглядит так же, как и в предыдущем примере.
Ключевой момент, о котором необходимо помнить при выполнении преобразований, состоит в том, чтобы не забыть использовать подходящее хранилище; XPathDocument, если не требуется редактирование, XmlDataDocument, если данные получают из ADO.NET, и XmlDocument, если необходимо иметь возможность редактировать данные. Процесс будет таким же, несмотря ни на что.
XML и ADO.NET
XML является средством, которое связывает ADO.NET с остальным миром. ADO.NET был создан для работы внутри среды XML. XML используется для преобразования данных в и из хранилища данных в приложение или страницу Web. Так как ADO.NET использует XML в качестве транспорта, то данными можно обмениваться с приложениями и системами, которые даже не знают об ADO.NET. Пока обрабатывается XML, они могут совместно использовать данные. ADO.NET может читать документы XML, возвращаемые из этих же приложений. В связи с важностью XML для ADO.NET, существует ряд полезных свойств ADO.NET, которые позволяют чтение и запись документов XML. Пространство имен XML содержит также классы, которые могут потреблять или утилизировать реляционные данные ADO.NET.
Данные ADO.NET в документе XML
Первый пример, который будет рассмотрен, использует потоки ADO.NET и XML для извлечения данных из базы данных Northwind в DataSet, загрузки объекта XmlDocument, содержащего XML, из DataSet, и загрузки XML в listbox аналогично тому, что делалось ранее. Чтобы выполнить несколько следующих примеров, необходимо добавить инструкции using:
using System.Data;
using System.Xml;
using System.Data.SqlClient;
using System.IO;
Также для примеров ADO в формы добавлены DataGrid, что позволит нам увидеть данные в DataSet из ADO.NET, так как они ограничены сеткой, а также данные из созданных документов XML, которые загружаются в listbox. Вот код первого примера, который можно найти в папке ADOSample1:
private void button1_Click(object sender, System.EventArgs e) {
// создать множество данных DataSet
DataSet ds=new DataSet("XMLProducts");
// соединиться с базой данных northwind и
//выбрать все строки из таблицы продуктов
//убедитесь, что имя пользователя соответствует версии SqlServer
SqlConnection conn=
new SqlConnection(@"server=GLYNNJ_CS\NetSDK;uid=sa;pwd=;database=northwind");
SqlDataAdapter da=new SqDataAdapter("select * from products", conn);
После создания SqlDataAdapter, da и DataSet, ds создаются экземпляры объекта MemoryStream, объекта StreamReader и объекта StreamWriter. Объекты StreamReader и StreamWriter будут применять MemoryStream для перемещения XML:
MemoryStream memStrm=new MemoryStream();
StreamReader strmRead=new StreamReader(memStrm);
StreamWriter strmWrite=new StreamWriter(memStrm);
Мы будем использовать MemoryStream, поэтому ничего на диск записываться не будет, однако мы сможем применять любые объекты на основе класса Stream, такие как FileStream. Затем мы заполним DataSet и свяжем его с DataGrid. Данные из DataSet будут выводиться теперь в DataGrid:
da.Fill(ds, "products");
// загрузка данных в DataGrid
dataGrid1.DataSource=ds;
dataGrid1.DataMember="products";
На следующем шаге генерируется XML. Вызывается метод WriteXml из класса DataSet. WriteXml генерирует документ XML. Существуют две перегружаемые версии WriteXml, одна получает строку с путем доступа и именем файла, а в другом методе добавлен параметр режима mode. Этот mode является перечислением XmlWriteMode. Возможными значениями являются DiffGram, IgnoreSchema, и WriteSchema. Обсудим DiffGram позже в этом разделе. IgnoreSchema используется, если нежелательно, чтобы WriteXml записывал подставляемую (inline) схему в файл XML; используйте параметр WriteSchema, если это желательно. Чтобы получить именно схему, вызывается WriteXmlSchema. Этот метод имеет четыре перегружаемые версии. Одна получает строку, содержащую путь доступа и имя файла, куда записывается документ XML. Вторая версия использует объект, который основывается на классе XmlWriter. Третья версия использует объект, который основывается на классе TextWriter. Четвертая версия используется в примере, параметр в этом случае является производным от класса Stream:
ds.WriteXml(strmWrite, XmlWriteMode.IgnoreSchema);
memStrm.Seek(0, SeekOrigin, Begin);