ГлавнаяРегистрацияВход Приветствую Вас Гость | RSS
   
Меню сайта
Разделы новостей
mp3player
Главная » 2007 » Июль » 8 » XML за 20 минут! (Часть 2)
XML за 20 минут! (Часть 2)
14:57
По материалам статьи Leon Platt: XML IN 20 MINUTES!
Перевод Максима Зубова
 
С помощью этой статьи, вы быстро погрузитесь в XML. Я буду брать предметы из повседневной жизни, и пытаться описывать их, используя XML. Затем я загружу файл XML в объектную модель документов XML. После этого я продемонстрирую, как запрашивать XML документы с помощью XPath и проделывать некоторые основные манипуляции над ними. Все эти действия будут продемонстрированы с использованием простого приложения на Visual Basic и Microsoft Parser версии 3.0. Заключительной целью этой статьи будет разработка элемента управления ActiveX , который будет запрашивать данные из базы данных pubs на SQL Server и возвращать список наименований книг в формате XML.
 

3. Преобразование ADO в XML

Теперь, когда вы поняли основы XML, давайте создадим элемент управления ActiveX, который будет конвертировать набор данных ADO в XML формат. Цель в том, чтобы получить наименования книг из таблицы Titles базы данных Pubs и вернуть их в формате XML. Результат, который получится я буду использовать в своей следующей статье. Вы можете сказать, ADO имеет свои собственные методы для сохранения результата в формате XML, правильно? Да, но если доверить это ADO, то в итоге я получу XML файл в таком ужасном формате, что с ним невозможно будет работать. ADO создаст XML файл с использованием пространства имен, а мне сейчас это совсем не нужно. Во-вторых, ADO создаст XML файл, который будет представлен в форме атрибутов. Иными словами, каждая запись станет элементом и каждое поле - атрибутом:


<xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'
 xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'
 xmlns:rs='urn:schemas-microsoft-com:rowset'
 xmlns:z='#RowsetSchema'>
<s:Schema id='RowsetSchema'>
 <s:ElementType name='row' content='eltOnly'>
 <s:AttributeType name='title_id' rs:number='1' rs:writeunknown='true'>
 <s:datatype dt:type='string' rs:dbtype='str' dt:maxLength='6' 
 rs:maybenull='false'/>
 </s:AttributeType>
 <s:AttributeType name='title' rs:number='2' rs:writeunknown='true'>
 <s:datatype dt:type='string' rs:dbtype='str' dt:maxLength='80' 
 rs:maybenull='false'/>
 </s:AttributeType>
 <s:AttributeType name='type' rs:number='3' rs:writeunknown='true'>
 <s:datatype dt:type='string' rs:dbtype='str' dt:maxLength='12' 
 rs:fixedlength='true' rs:maybenull='false'/>
 </s:AttributeType>
 <s:AttributeType name='price' rs:number='4' rs:nullable='true' 
 rs:writeunknown='true'>
 <s:datatype dt:type='number' rs:dbtype='currency' dt:maxLength='8' 
 rs:precision='19' rs:fixedlength='true'/>
 </s:AttributeType>
 <s:AttributeType name='ytd_sales' rs:number='5' rs:nullable='true' 
 rs:writeunknown='true'>
 <s:datatype dt:type='int' dt:maxLength='4' rs:precision='10' 
 rs:fixedlength='true'/>
 </s:AttributeType>
 <s:AttributeType name='notes' rs:number='6' rs:nullable='true' 
 rs:writeunknown='true'>
 <s:datatype dt:type='string' rs:dbtype='str' dt:maxLength='200'/>
 </s:AttributeType>
 <s:AttributeType name='pubdate' rs:number='7' rs:writeunknown='true'>
 <s:datatype dt:type='dateTime' rs:dbtype='timestamp' dt:maxLength='16' 
 rs:scale='3' rs:precision='23' rs:fixedlength='true'
 rs:maybenull='false'/>
 </s:AttributeType>
 <s:extends type='rs:rowbase'/>
 </s:ElementType>
</s:Schema>
<rs:data>
 <z:row title_id='BU1032' title='The Busy Executive's 
 Database Guide' type='business ' price='19.99'
 ytd_sales='4095' notes='An overview of available database systems with 
 emphasis on common business applications. Illustrated.'
 pubdate='1991-06-12T00:00:00'/>
 <z:row title_id='BU1111' title='Cooking with Computers: Surreptitious 
 Balance Sheets' type='business ' price='11.95'
 ytd_sales='3876' notes='Helpful hints on how to use your 
 electronic resources to the best advantage.' 
 pubdate='1991-06-09T00:00:00'/>
</rs:data>
</xml>

А мне бы хотелось получить XML файл в форме элементов, где каждая запись, содержалась бы в теге <BOOK>, и каждое поле было бы элементом внутри тега <BOOK>. Синтаксис моей XML строки был бы таким:


<TITLES>
<BOOK>data from table
<FIELD prettyname="Book identification number" tablename="titles" 
 columnname="title_id" datatype="number" filter="">data from table</FIELD>
<FIELD prettyname="Title of the book" tablename="titles" 
 columnname="title" datatype="text" filter="">data from table</FIELD>
<FIELD prettyname="Type of book" tablename="titles" columnname="type" 
 datatype="text" filter="">data from table</FIELD>
<FIELD prettyname="Price of the book" tablename="titles" 
 columnname="price" datatype="number" filter="">data from table</FIELD>
<FIELD prettyname="Year todate sales" tablename="titles" columnname="ytd_sales" 
 datatype= "number" filter= "">datafrom table</FIELD>
<FIELD prettyname="Datepublished" tablename= "titles" columnname="pubdate" 
 datatype="date" filter= "">datafromtable</FIELD>
 </BOOK>
</TITLES>

Кстати, то, что я только что сделал, это создал схему для моей XML строки. Теперь, если мне нужно сверить структуру XML документа со схемой, все что мне останется сделать, это преобразовать схему в правильный формат. То есть в синтаксис DTD или XDR. Заметьте, что я добавил некоторые атрибуты к каждому элементу <FIELD>. Одна из причин этого в том, что эта информация может быть использована клиентом. Prettyname могут быть использованы как метки данных. Атрибут datatype мог бы быть использован для проверки данных на стороне клиента. Но чтобы быть честным, истина причина того, что появились эти атрибуты в том, что они имеют особое назначение в шаблоне XSL фала, который я часто использую для построения секции where SQL запросов. Может быть, я скоро опубликую статью, демонстрирующую этот подход. Шаблон на самом деле очень полезный. Когда XML структура применяется к данным из таблицы Titles, результат будет выглядеть следующим образом:


<TITLES>
 <BOOK>The Busy Executive's Database Guide
 <FIELD prettyname="Title Identification Number" tablename="titles" 
 gcolumnname="title_id" datatype="number" gfilter="">BU1032</FIELD>
 <FIELD prettyname="Title of the Book" tablename="titles" 
 gcolumnname="title" datatype="text" gfilter="">
 The Busy Executive's Database Guide</FIELD>
 <FIELD prettyname="Type of Book" tablename="titles" gcolumnname="type" 
 datatype="text" gfilter="">business</FIELD>
 <FIELD prettyname="Price of the Book" tablename="titles" 
 gcolumnname="price" datatype="number" gfilter="">19.99</FIELD>
 <FIELD prettyname="Year to date sales" tablename="titles" 
 gcolumnname="ytd_sales" datatype="number" gfilter="">4095</FIELD>
 <FIELD prettyname="Notes about the book" tablename="titles" 
 gcolumnname="notes" datatype="memo" gfilter="">
 An overview of available database systems with emphasis on common business 
 applications. Illustrated.</FIELD>
 <FIELD prettyname="Date Published" tablename="titles" 
 gcolumnname="pubdate" datatype="date" gfilter="">6/12/1991</FIELD>
 </BOOK>
 <BOOK>Cooking with Computers: Surreptitious Balance Sheets
 <FIELD prettyname="Title Identification Number" tablename="titles" 
 gcolumnname="title_id" datatype="number" gfilter="">BU1111</FIELD>
 <FIELD prettyname="Title of the Book" tablename="titles" 
 gcolumnname="title" datatype="text" gfilter="">Cooking with Computers: 
 Surreptitious Balance Sheets</FIELD>
 <FIELD prettyname="Type of Book" tablename="titles" gcolumnname="type" 
 datatype="text" gfilter="">business</FIELD>
 <FIELD prettyname="Price of the Book" tablename="titles" 
 gcolumnname="price" datatype="number" gfilter="">11.95</FIELD>
 <FIELD prettyname="Year to date sales" tablename="titles" 
 gcolumnname="ytd_sales" datatype="number" gfilter="">3876</FIELD>
 <FIELD prettyname="Notes about the book" tablename="titles" 
 gcolumnname="notes" datatype="memo" gfilter="">Helpful hints on 
 how to use your electronic resources to the best advantage.</FIELD>
 <FIELD prettyname="Date Published" tablename="titles" 
 gcolumnname="pubdate" datatype="date" gfilter="">6/9/1991</FIELD>
 </BOOK>
</TITLES>

Теперь я получил что-то, с чем можно работать!

Листинг 1 - CUP.XML


<?xml version="1.0"?>
<CUP>
<MATERIAL transparent="yes">glass</MATERIAL>
<HEIGHT units="inches">6</HEIGHT>
<VOLUME units="ounces">16</VOLUME>
<CONTENTS>
 <SOLID qty="2">ice cube</SOLID>
 <SOLID qty="1">straw</SOLID>
 <LIQUID qty="3" units="ounces">water</LIQUID>
 <OTHER qty="0"/>
</CONTENTS>
<LID>yes</LID>
</CUP>

Листинг 2 - Загрузка Cup.xml в объектную модель документов


Dim xmlDoc As MSXML2.DOMDocument30
Set xmlDoc = New DOMDocument30
xmlDoc.async = False
xmlDoc.validateOnParse = False
xmlDoc.Load ("c:inetpubwwwrootxmlcup.xml")
MsgBox xmlDoc.xml
Dim objNode As IXMLDOMNode
Dim objListOfNodes As IXMLDOMNodeList
xmlDoc.setProperty "SelectionLanguage", "XPath"
MsgBox "Your cup contains the following items"
Set objListOfNodes = xmlDoc.selectNodes("//CONTENTS/*[@qty>0]")
For Each objNode In objListOfNodes
MsgBox objNode.Text
Next
Set objNode = xmlDoc.selectSingleNode("/CUP/LID")
If objNode.Text = "yes" Then
MsgBox "We have a lid"
Else
MsgBox "No lid on this cup"
End If

Листинг 3 - Элемент управления ActiveX: ADO в XML (WebClass.dll)(xmlControl.cls)


Option Explicit

'Declare Database variables
Private m_dbConnection As New ADODB.Connection
Private m_dbCommand As ADODB.Command
Private m_adoRs As ADODB.Recordset
Private m_adoErrors As ADODB.Errors
Private m_adoErr As Error
Public nCommandTimeOut As Variant
Public nConnectionTimeOut As Variant
Public strConnect As Variant
Public strAppName As String
Public strLogPath As String
Public strDatabase As String
Public strUser As String
Public strPassword As String
Public strServer As String
Public strVersion As String
Public lMSADO As Boolean
'Private Global Variables
Private gnErrNum As Variant
Private gstrErrDesc As Variant
Private gstrErrSrc As Variant
Private gstrDB As String
Private gstrADOError As String
Private Const adLeonNoRecordset As Integer = 129
Private gtableName(6) As String
Private gcolumnName(6) As String
Private gprettyName(6) As String
Private gdatatype(6) As String
Private gfilter(6) As String

Private Function OpenDatabase()

If Len(strConnect) = 0 Then 'устанавливаем значения по умолчанию
If Len(strDatabase) = 0 Then
strDatabase = "pubs"
End If

If nConnectionTimeOut = 0 Then
nConnectionTimeOut = 600
End If

If nCommandTimeOut = 0 Then
nCommandTimeOut = 600
End If

If Len(strAppName) = 0 Then
strAppName = "xmlControl"
End If

If Len(strUser) = 0 Then
strUser = "sa"
End If

If Len(strPassword) = 0 Then
strPassword = ""
End If

strConnect = "Provider=SQLOLEDB.1; " & _
 "Application Name=" & strAppName & _
 "; Data Source=" & strServer & "; Initial Catalog=" & strDatabase & "; " & _
 " User ID=" & strUser & "; Password=" & strPassword & ";"
End If

 'подключаемся к SQL Server и открываем базу данных
On Error GoTo SQLErr 'Включаем обработчик ошибок
With m_dbConnection
.ConnectionTimeout = nConnectionTimeOut
.CommandTimeout = nCommandTimeOut
.Open strConnect 'открываем базу данных, используя строку подключения
End With
On Error GoTo 0 'выключаем обработчик ошибок

OpenDatabase = True 'база данных открыта успешно

Exit Function

SQLErr:
Call logerror("OPEN")
OpenDatabase = False

End Function

Private Function BuildSQLwhere(tmpWhere) As String

 'Это на будущее

End Function

Public Function GetTitlesXML(Optional xmlWhere As Variant) As String

Dim whereClause As String
Dim strSQL As String

Call OpenDatabase 'открываем базу данных pubs

If IsMissing(xmlWhere) Then 'когда запрос не прошел
whereClause = ""
Else
whereClause = BuildSQLwhere(xmlWhere)'конвертируем запрос в правильный sql
End If

 'инициализируем sql выражение которое будет запрашивать заголовки книг
strSQL = "select title_id,title,type,price,ytd_sales,notes,pubdate from titles " & whereClause

Call NewRecordSet 'создаем набор данных
 'устанавливаем cursorlocation
m_adoRs.CursorLocation = adUseClient
 'открываем набор записей
m_adoRs.Open strSQL, m_dbConnection, adOpenForwardOnly, adLockReadOnly, adCmdText

 'отключаемся от набора данных
Set m_adoRs.ActiveConnection = Nothing

On Error GoTo 0 'выключаем обработчик ошибок

 'закрываем базу данных и освобождаем подключение
Call CloseDatabase

If m_adoRs.EOF Then
GetTitlesXML = "" 'запрос не вернул ни одного значения
Else
If lMSADO Then
GetTitlesXML = msado(m_adoRs) 'конвертируем набор данных в Microsoftado-->xml
Else
GetTitlesXML = ADOtoXML(m_adoRs, True) 'convert the ado recordset to custom xml
End If
End If

 'закрываем набор данных
Call CloseRecordset

Exit Function

SQLErr:
Call logerror(strSQL)

End Function

Private Function ADOtoXML(tmprs As ADODB.Recordset, tmpMP As Boolean) As String

Dim adoFields As ADODB.Fields 'объявляем коллекцию для хранения полей
Dim adoField As ADODB.Field 'используется для получения каждого поля из коллекции
Dim xmlDoc As msxml2.DOMDocument30
Dim tmpLine As String 'хранит xml представление каждой книги
Dim tmpXML As String 'служит для конкатенации xml строк
Dim i As Integer

If tmprs.EOF Then 'запрос не вернул ни одну запись
ADOtoXML = ""
Exit Function
Else
Set adoFields = tmprs.Fields 'создаем коллекцию полей
End If

tmpXML = "<TITLES>" 'все книги будет заключены в тег <TITLES>

Do Until tmprs.EOF 'цикл по каждой строке в наборе данных
i = 0 ' I - индекс ado поля, который начинается с 0 - первое поле будет field(0)
tmpLine = "<BOOK>" & tmprs("title") & vbCrLf
For Each adoField In adoFields 'цикл по всем полям
 'строим xml тег <FIELD> и его атрибуты для текущего поля
tmpLine = tmpLine & "<FIELD " 
tmpLine = tmpLine & "prettyname=""" & gprettyName(i) & """ "
tmpLine = tmpLine & "tablename=""" & gtableName(i) & """ 
 gcolumnname=""" & adoField.Name & """ "
tmpLine = tmpLine & "datatype=""" & gdatatype(i) & """ gfilter="""""
tmpLine = tmpLine & ">" & adoField.Value
tmpLine = tmpLine & "</FIELD>" & vbCrLf
i = i + 1 'переходим на следующее поле
Next
tmpXML = tmpXML & tmpLine & "</BOOK>" & vbCrLf 'закрывающий тег после последнего поля
tmprs.MoveNext 'следующий заголовок
Loop
Set adoField = Nothing 'уничтожаем объект-поле
Set adoFields = Nothing 'уничтожаем объект-коллекцию полей

tmpXML= tmpXML & "<?xml version="1.0"?></TITLES>" & vbCrLf 'закрывающий тег </TITLES>
Set xmlDoc = New msxml2.DOMDocument30 'создание xmlDOM 
xmlDoc.async = False 'ждем когда документ загрузится
xmlDoc.validateOnParse = False 'не сверяемся со схемой
xmlDoc.loadXML(tmpXML) 'загружаем строку в объектную модель документов
On Error Resume Next 'если файл не существует, то обрабатываем эту ошибку
Kill("c:tempcustom.xml") 'стираем файл если он существует 
On Error GoTo 0 'говорим обработчику ошибок прерываться при обнаружении ошибки 
xmlDoc.save ("c:tempcustom.xml") 'сохраняем xml в файл
ADOtoXML=xmlDoc.xml 'возвращает xml строку
Set xmlDoc=Nothing 'уничтожаем объектную модель документов

End Function 

Private Function msado(tmprs As ADODB.Recordset) As String 

Dim xmlDoc As msxml2.DOMDocument30
On Error Resume Next 'если файла не существует, получаем ошибку
Kill ("c:tempmsado.xml") 'стираем файл, если он существует
On Error GoTo 0 ' говорим обработчику ошибок прерываться при обнаружении ошибки
tmprs.save "c:tempmsado.xml", adPersistXML ' сохраняем xml в файл
Set xmlDoc = New msxml2.DOMDocument30 'создаем объектную модель документов xml
xmlDoc.async = False 'ждем загрузки xml документа
xmlDoc.validateOnParse = False 'не сверяемся со схемой
xmlDoc.Load ("C:tempmsado.xml") 'загружаем файл в объектную модель документов
msado = xmlDoc.xml 'возвращаем xml строку
Set xmlDoc = Nothing 'уничтожаем объектную модель документов

End Function 

Private SubCloseRecordset() 
 
 'закрываем набор данных 
m_adoRs.Close 
Set m_adoRs =Nothing 

End Sub 

Private Sub NewRecordSet() 

Set m_adoRs= Nothing 
Set m_adoRs=New ADODB.Recordset

End Sub 

Private Sub CloseDatabase() 

m_dbConnection.Close
Set m_dbConnection =Nothing 

End Sub 

Private Sub logerror(errSQL As String)
 
Dim hFile As Integer
Dim expFile As String
 
On Error GoTo 0
gnErrNum = Err.Number 
gstrErrDesc =Err.Description 
gstrErrSrc = Err.Source Set
m_adoErrors = m_dbConnection.Errors 

For Each m_adoErr In m_adoErrors
 gstrADOError = m_adoErr.Description & "," & CStr(m_adoErr.NativeError)
 _ & "," & CStr(m_adoErr.Number) & "," &
 m_adoErr.Source _ & "," & CStr(m_adoErr.SQLState)
Next 

hFile =FreeFile
If Len(strLogPath) = 0 Then 
strLogPath = "C:temp" 
End If 
expFile = strLogPath & strAppName & ".err" 
Open expFile For Append As #hFile

Print #hFile,"**********************************" 
Print #hFile, Now() 
Print#hFile, "**********************************" 
Print #hFile,"Subroutine: " & tmpPro
Print #hFile, "Error Number:" & gnErrNum 
Print#hFile, "Error Description: " & gstrErrDesc 
Print #hFile, "Error Source:" & gstrErrSrc 
Print #hFile, "Ado error String: " & gstrADOError 
Print #hFile, "Bad SQL: " & errSQL 
Close #hFile
End Sub 

 Private Sub Class_Initialize() 
strVersion = "xmlControl Version 1.1" 
 'title_id,title,type,price,ytd_sales,notes,pubdate
gtableName(0) = "titles"
gcolumnName(0) = "title_id"
gprettyName(0) = "Title Identification Number"
gdatatype(0) = "number"
gfilter(0) = ""
gtableName(1) = "titles"
gcolumnName(1) = "title"
gprettyName(1) = "Title of the Book"
gdatatype(1) = "text"
gfilter(1) = ""
gtableName(2) = "titles"
gcolumnName(2) = "type"
gprettyName(2) = "Type of Book"
gdatatype(2) = "text"
gfilter(2) = ""
gtableName(3) = "titles"
gcolumnName(3) = "price"
gprettyName(3) = "Price of the Book"
gdatatype(3) = "number"
gfilter(3) = ""
gtableName(4) = "titles"
gcolumnName(4) = "ytd_sales"
gprettyName(4) = "Year to date sales"
gdatatype(4) = "number"
gfilter(4) = ""
gtableName(5) = "titles"
gcolumnName(5) = "notes"
gprettyName(5) = "Notes about the book"
gdatatype(5) = "memo"
gfilter(5) = ""
gtableName(6) = "titles"
gcolumnName(6) = "pubdate"
gprettyName(6) = "Date Published"
gdatatype(6) = "date"
gfilter(6) = ""

End Sub

Листинг 4 - Тестовое приложение на VB для проверки WebClass


Private Sub Command1_Click()

Dim objWC As xmlControl
Dim xml As String
Set objWC = New xmlControl
objWC.strDatabase = "pubs"
objWC.strServer = "ltweb"
objWC.strUser = "sa"
objWC.strPassword = ""
objWC.lMSADO = Option2.Value
objWC.strAppName = "Article1"
Text1.Text = objWC.getTitlesXML

End Sub

Листинг 5 - ASP для тестирования WebClass


<%@ Language=VBScript %>
<%
 'Используем WebClass элемента управления ActiveX чтобы вернуть xml в браузер
 '
 'до того, как со страницей можно будет работать, WebClass.dll должен быть зарегистрирован 
 'на вэб-сервере.
 'Анализатор microsoft xml версии 3.0 (msxml3.dll) тоже должен быть зарегистрирован
 '
set objWC = Server.CreateObject("WebClass.xmlControl")
objWC.strDatabase = "pubs"
objWC.strServer = "ltweb" 'замените ltweb именем вашего SQL сервера
objWC.strUser ="sa" 'замените sa именем пользователя вашего SQL сервера
objWC.strPassword="" 'сюда введите пароль для этого пользователя
objWC.strAppName="Article1"
objWC.lMSADO=false 'true вернет microsoft ado-->xml
 'false вернет пользовательский xml
 '
Response.ContentType="text/xml" 'устанавливаем тип содержимого для браузера
Response.write objWC.getTitlesXML 'получаем the xml отображаем его
 '
set objWC=nothing 'уничтожаем объект
%>


Категория: XML | Просмотров: 734 | Добавил: VVS | Рейтинг: 0.0/0 |
Всего комментариев: 0
Имя *:
Email *:
Код *:
Поиск
Форма входа
Наш опрос
Чего Вам не хватает на сайте?
Всего ответов: 21
Друзья сайта
Статистика
Возраст