Набор строк XML и MsXML2
У меня есть набор строк, возвращаемый с использованием схемы набора строк Microsoft из моей системы управления запасами.
Однако при использовании msxml2 для чтения документа я не могу получить доступ к данным (написано в vbscript)
<xml>
<s:schema>
<!-- Schema here -->
</s:schema>
<rs:data>
<z:row field="value" field1="value" />
</rs:data>
</xml>
Чтобы вернуть это, я использую:
Set objXmlHttp = Server.CreateObject("Msxml2.ServerXMLHTTP")
objXmlHttp.open "POST", address, False
objXmlHttp.setRequestHeader "Content-Type", "text/xml"
objXmlHttp.Send strXml
Set objLst = XML_response.getElementsByTagName("data")
myValue = objLst.item(0).getAttribute("field")
Однако я получаю следующее сообщение:
Microsoft VBScript runtime error '800a01a8'
Object required: 'objLst.item(...)'
Это, вероятно, я делаю что-то совершенно не так, если так, может кто-то указал мне, пожалуйста, потому что я смотрю на это в течение 2 часов, и я не могу понять это.
2 ответа
Учитывая таблицу как:
SELECT TOP 5 * FROM [actor.txt]
----------------------------------------------------------------
|actor_id|first_name|last_name |last_update |
| 1|PENELOPE |GUINESS |2/15/2006 4:34:33 AM|
| 2|NICK |WAHLBERG |2/15/2006 4:34:33 AM|
| 3|ED |CHASE |2/15/2006 4:34:33 AM|
| 4|JENNIFER |DAVIS |2/15/2006 4:34:33 AM|
| 5|JOHNNY |LOLLOBRIGIDA|2/15/2006 4:34:33 AM|
----------------------------------------------------------------
в доступной базе данных ADO (классическая, протестированная с версией 2.8) вы можете сохранить набор результатов в XML, используя
oRS.Save sFSpec, adPersistXML
Это дает вам 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='actor_id' rs:number='1' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='i2' dt:maxLength='2' rs:precision='5' rs:fixedlength='true'/>
</s:AttributeType>
<s:AttributeType name='first_name' rs:number='2' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='string' dt:maxLength='45'/>
</s:AttributeType>
<s:AttributeType name='last_name' rs:number='3' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='string' dt:maxLength='45'/>
</s:AttributeType>
<s:AttributeType name='last_update' rs:number='4' rs:nullable='true' rs:maydefer='true' rs:writeunknown='true'>
<s:datatype dt:type='dateTime' rs:dbtype='variantdate' dt:maxLength='16' rs:fixedlength='true'/>
</s:AttributeType>
<s:extends type='rs:rowbase'/>
</s:ElementType>
</s:Schema>
<rs:data>
<z:row actor_id='1' first_name='PENELOPE' last_name='GUINESS' last_update='2006-02-15T04:34:33'/>
<z:row actor_id='2' first_name='NICK' last_name='WAHLBERG' last_update='2006-02-15T04:34:33'/>
<z:row actor_id='3' first_name='ED' last_name='CHASE' last_update='2006-02-15T04:34:33'/>
<z:row actor_id='4' first_name='JENNIFER' last_name='DAVIS' last_update='2006-02-15T04:34:33'/>
<z:row actor_id='5' first_name='JOHNNY' last_name='LOLLOBRIGIDA' last_update='2006-02-15T04:34:33'/>
</rs:data>
</xml>
Чтобы прочитать эти данные, начните с (локального, консольного) кода, например:
Dim oFS : Set oFS = CreateObject( "Scripting.FileSystemObject" )
Dim sDDir : sDDir = oFS.GetAbsolutePathName( "..\Data" )
Dim sFSpec : sFSpec = oFS.GetAbsolutePathName( "..\Data\actor.xml" )
Dim oXDoc : Set oXDoc = CreateObject("msxml2.domdocument")
Dim sXPath, ndFnd, ndlFnd, attrX, nIdx
oXDoc.async = False
oXDoc.validateOnParse = False
oXDoc.resolveExternals = False
oXDoc.setProperty "SelectionLanguage", "XPath"
oXDoc.setProperty "SelectionNamespaces", Join( Array( _
"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'" _
), " ")
If oXDoc.load(sFSpec) Then
WScript.Echo sFSpec, "looks good."
For Each sXPath In Array( _
"/xml" _
, "/xml/s:Schema" _
, "/xml/rs:data" _
, "/xml/rs:data/z:row[@actor_id=""2""]" _
)
WScript.Stdout.Write "|" & sXPath & "| => "
Set ndFnd = oXDoc.selectSingleNode( sXPath )
If ndFnd Is Nothing Then
WScript.Stdout.WriteLine "not found"
Else
WScript.Stdout.WriteLine "found a(n) " & ndFnd.tagName
End If
Next
WScript.Echo "-----------------------"
'<rs:data>
' <z:row actor_id='1' first_name='PENELOPE' last_name='GUINESS' last_update='2006-02-15T04:34:33'/>
' ...
'</rs:data>
sXPath = "/xml/rs:data/z:row[@actor_id=""3""]"
Set ndFnd = oXDoc.selectSingleNode( sXPath )
If ndFnd Is Nothing Then
WScript.Echo "|", sXPath, "| not found"
Else
For Each attrX In ndFnd.Attributes
WScript.Echo attrX.Name, attrX.Value
Next
End If
WScript.Echo "-----------------------"
sXPath = "/xml/rs:data/z:row"
Set ndlFnd = oXDoc.selectNodes( sXPath )
If ndlFnd Is Nothing Then
WScript.Echo "ndlFnd Is Nothing"
Else
If 0 = ndlFnd.Length Then
WScript.Echo "ndlFnd is empty"
Else
For Each ndFnd In ndlFnd
WScript.Echo TypeName(ndFnd)
For Each attrX In ndFnd.Attributes
WScript.Echo "", attrX.Name, attrX.Value
Next
Next
End If
End If
Else
WScript.Echo "Bingo!"
WScript.Echo oXDoc.parseError.reason
End If
Важные шаги:
- Для разработки / тестирования избегайте лишней сложности использования сервера; если cscript readxml.vbs успешно выполняется, легко "перенести" рабочий код на.asp (и отдельно решать специфичные для сервера проблемы)
- Создайте msxml2.domdocument
- Настройте это; особенно скопируйте пространства имен из тега xml в пространства имен SelectionName
- Загрузите файл, проверьте на ошибки
- Укажите выражения XPath (осторожно!, попробуйте "перевести" XML из вашего образца в XPATH)
- Проверьте результаты.selectSingleNode() и.selectNodes()
- Доступ к атрибутам, содержащим данные
Предположим, что опубликованный вами XML a) содержит правильные псевдонимы пространства имен и b) загружен в XML_response
правильно.
Теперь "правильный" способ сделать это - использовать XPath, однако мы можем достичь наших целей с помощью более простого кода в этом случае. Язык выбора по умолчанию в MSXML (3 или ниже) - XSL Pattern, этот выбор не понимает псевдонимы пространства имен, поэтому <rs:data>
имеет имя тега "rs:data", а не "data" с его точки зрения. Это первое, что вы делаете неправильно.
Другое дело, что getElementsByTag
возвращает коллекцию узлов, которая содержит только один узел "rs:data". Ваш код пытается прочитать атрибут "field" из того узла, где он находится на дочернем узле "z:row".
Вот как должен выглядеть ваш код:
Dim objData: Set objData = XML_response.documentElement.selectSingleNode("rs:data")
Dim row
Dim fieldVal, field1Val
For Each row in objData.selectNodes("z:row")
fieldVal = row.getAttribute("field")
field1Val = row.getAttribute("field1")
''# Do stuff with your fields for each row found.
Next