(SQL) SQL (2009 год)

Как парсить XML SOAP в MS SQL

В отличие от более простого MySQL, у MS SQL даже в Express версии есть достаточно реальная поддержка XML. В PostgreSQL такая поддержка в принципе тоже есть, но в виде отдельных пакетов.

С помощью XML-поддержки можно сделать много полезного в MS SQL - многое но не все! В самый нужный момент микрософтовцы как всегда затупили. Билл Гейтс даже принял на работу к себе 700 копрофилов и зоофилов в надежде, что интеллектуальный потенциал микрософта хоть чуть-чуть увеличится, но увы, даже они не додумались подсказать главного - по стандарту XML идентификаторы могут иметь минус внутри идентификатора неймспейса схемы. Впрочем, мы все знаем, что ни билогейтсовские копрофилы, ни зоофилы, ни все остальные микрософтовцы интернет-стандартов никогда не читали.

Итак, что же все-таки возможно сделать с помощью встроенной в MS SQL поддержки XML?


C помощью встроенной в MS SQL поддержки XPATH-выражений можно довольно удобно распарсить простейшие XML :


   1:  ALTER View [dbo].[GetOperator]
   2:  as
   3:  select ID,GroupID,CyberID,SourceOrder,
   4:  Node.value('/operator[1]/name[1]', 'nvarchar(256)') as [name],
   5:  Node.value('/operator[1]/name_for_cheque[1]', 'nvarchar(256)') as [name_for_cheque],
   6:  Node.value('/operator[1]/inn_for_cheque[1]', 'nvarchar(256)')as [inn_for_cheque],
   7:  Node.value('/operator[1]/comission[1]/@amount', 'int')as [comission],
   8:  Node.value('/operator[1]/limit[1]/@min', 'int')as [min],
   9:  Node.value('/operator[1]/limit[1]/@max', 'int')as [max],
  10:  Node.value('/operator[1]/image[1]', 'nvarchar(256)')as [image],
  11:  Node.value('/operator[1]/rootmenuimage[1]', 'nvarchar(256)')as [rootmenuimage],
  12:  Node.query('/operator/fields')as [fields],
  13:  Node.query('/operator/processor')as [processor]
  14:  from dbo.MobileOperator


Однако, на практике, увы, как правило возникают гораздо более сложные задачи. Как бы для них предусмотрена конструкция WITH NAMESPACE, однако она не поддерживает совершенно обычные стандартные идентификаторы схем. Да и выгребать вручную идентификаторы замучаешься. А если схема то одна, то другая? Как динамически менять схемы в уродской конструкции WITH NAMESPACE?


Здесь на помощь придут только SQL CLR сборки, о которых много сказано на моем сайте Однако, делать полностью универсальную сборку - которой бы могли воспользоваться все, я не вижу смысла. У нее будет слишком гиморойный синтаксис вызова. Я вижу смысл только автоматизировать выгребание неймспейсов, а собственно вписывание XPATH выражений оставить на откуп пользователю.

Таким образом, ниже я покажу сборку, которая распарсит стандартный SOAP и вернет вместо XML просто табличку:

Обратите внимание, что это как раз противоположная операция преобразования от другой распространенной операции, многократно описанной на моем сайте - Этюды на ASP2. Делаем RSS-канал на одной SQL-процедуре - когда требуется реляционные данные преобразовать в XML (тоже на уровне SQL).

Итак, вот долгожданное чудо - код SQL CLR сборки с табличным возвратом (на примере парсинга SOAP-ответа платежного сервиса Assist):


   1:  Imports System
   2:  Imports System.Data
   3:  Imports System.Data.SqlClient
   4:  Imports System.Data.SqlTypes
   5:  Imports Microsoft.SqlServer.Server
   6:   
   7:  Friend Class OneRow
   8:      Public i As Integer
   9:      Public ordernumber As String
  10:      Public response_code As String
  11:      Public recommendation As String
  12:      Public message As String
  13:      Public comment As String
  14:      Public [date] As String
  15:      Public total As String
  16:      Public currency As String
  17:      Public cardtype As String
  18:      Public cardnumber As String
  19:      Public lastname As String
  20:      Public firstname As String
  21:      Public middlename As String
  22:      Public address As String
  23:      Public email As String
  24:      Public country As String
  25:      Public rate As String
  26:      Public approvalcode As String
  27:      Public cardsubtype As String
  28:      Public cvc2 As String
  29:      Public cardholder As String
  30:      Public ipaddress As String
  31:      Public protocoltypename As String
  32:      Public billnumber As String
  33:      Public bankname As String
  34:      Public status As String
  35:      Public error_code As String
  36:      Public error_comment As String
  37:      Public packetdate As String
  38:      Public processingname As String
  39:      Public paymenttransactiontype_id As String
  40:      Public faultcode As String
  41:      Public faultstring As String
  42:   
  43:      Public Sub New(ByVal DR As SqlDataReader)
  44:          Try
  45:              i = CInt(DR(0))
  46:              '
  47:              'Распарсили ответ
  48:              If IsDBNull(DR(1)) Then
  49:                  Exit Sub
  50:              ElseIf DR(1).ToString.Contains("faultcode") Then
  51:                  'сообщение об ошибке авторизации
  52:                  Dim NameSpaceParcer2 As New ParceNamespace(DR(1).ToString)
  53:                  Dim _FaultCode As System.Xml.XmlNode = NameSpaceParcer2.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault/faultcode", NameSpaceParcer2.NamespaceManager)
  54:                  Dim _FaultString As System.Xml.XmlNode = NameSpaceParcer2.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault/faultstring", NameSpaceParcer2.NamespaceManager)
  55:                  '
  56:                  faultcode = _FaultCode.InnerText
  57:                  faultstring = _FaultString.InnerText
  58:                  '
  59:              ElseIf DR(1).ToString.Contains("<ASS-NS:GetPaymentsResultResponse") Then
  60:                  'нормальный ответ
  61:                  Dim NameSpaceParcer As New ParceNamespace(DR(1).ToString)
  62:                  Dim _Ordernumber As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/ordernumber", NameSpaceParcer.NamespaceManager)
  63:                  Dim _Response_code As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/response_code", NameSpaceParcer.NamespaceManager)
  64:                  Dim _Recommendation As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/recommendation", NameSpaceParcer.NamespaceManager)
  65:                  Dim _Message As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/message", NameSpaceParcer.NamespaceManager)
  66:                  Dim _Comment As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/comment", NameSpaceParcer.NamespaceManager)
  67:                  Dim _Date As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/date", NameSpaceParcer.NamespaceManager)
  68:                  Dim _Total As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/total", NameSpaceParcer.NamespaceManager)
  69:                  Dim _Currency As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/currency", NameSpaceParcer.NamespaceManager)
  70:                  Dim _Cardtype As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/cardtype", NameSpaceParcer.NamespaceManager)
  71:                  Dim _Cardnumber As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/cardnumber", NameSpaceParcer.NamespaceManager)
  72:                  Dim _Lastname As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/lastname", NameSpaceParcer.NamespaceManager)
  73:                  Dim _Firstname As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/firstname", NameSpaceParcer.NamespaceManager)
  74:                  Dim _Middlename As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/middlename", NameSpaceParcer.NamespaceManager)
  75:                  Dim _Address As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/address", NameSpaceParcer.NamespaceManager)
  76:                  Dim _Email As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/email", NameSpaceParcer.NamespaceManager)
  77:                  Dim _Country As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/country", NameSpaceParcer.NamespaceManager)
  78:                  Dim _Rate As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/rate", NameSpaceParcer.NamespaceManager)
  79:                  Dim _Approvalcode As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/approvalcode", NameSpaceParcer.NamespaceManager)
  80:                  Dim _Cardsubtype As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/cardsubtype", NameSpaceParcer.NamespaceManager)
  81:                  Dim _Cvc2 As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/cvc2", NameSpaceParcer.NamespaceManager)
  82:                  Dim _Cardholder As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/cardholder", NameSpaceParcer.NamespaceManager)
  83:                  Dim _Ipaddress As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/ipaddress", NameSpaceParcer.NamespaceManager)
  84:                  Dim _Protocoltypename As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/protocoltypename", NameSpaceParcer.NamespaceManager)
  85:                  Dim _Billnumber As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/billnumber", NameSpaceParcer.NamespaceManager)
  86:                  Dim _Bankname As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/bankname", NameSpaceParcer.NamespaceManager)
  87:                  Dim _Status As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/status", NameSpaceParcer.NamespaceManager)
  88:                  Dim _Error_code As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/error_code", NameSpaceParcer.NamespaceManager)
  89:                  Dim _Error_comment As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/error_comment", NameSpaceParcer.NamespaceManager)
  90:                  Dim _Packetdate As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/packetdate", NameSpaceParcer.NamespaceManager)
  91:                  Dim _Processingname As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/processingname", NameSpaceParcer.NamespaceManager)
  92:                  Dim _Paymenttransactiontype_id As System.Xml.XmlNode = NameSpaceParcer.XML.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/ASS-NS:GetPaymentsResultResponse/return/payment/paymenttransactiontype_id", NameSpaceParcer.NamespaceManager)
  93:                  '
  94:                  ordernumber = _Ordernumber.InnerText
  95:                  response_code = _Response_code.InnerText
  96:                  recommendation = _Recommendation.InnerText
  97:                  message = _Message.InnerText
  98:                  comment = _Comment.InnerText
  99:                  [date] = _Date.InnerText
 100:                  total = _Total.InnerText
 101:                  currency = _Currency.InnerText
 102:                  cardtype = _Cardtype.InnerText
 103:                  cardnumber = _Cardnumber.InnerText
 104:                  lastname = _Lastname.InnerText
 105:                  firstname = _Firstname.InnerText
 106:                  middlename = _Middlename.InnerText
 107:                  address = _Address.InnerText
 108:                  email = _Email.InnerText
 109:                  country = _Country.InnerText
 110:                  rate = _Rate.InnerText
 111:                  approvalcode = _Approvalcode.InnerText
 112:                  cardsubtype = _Cardsubtype.InnerText
 113:                  cvc2 = _Cvc2.InnerText
 114:                  cardholder = _Cardholder.InnerText
 115:                  ipaddress = _Ipaddress.InnerText
 116:                  protocoltypename = _Protocoltypename.InnerText
 117:                  billnumber = _Billnumber.InnerText
 118:                  bankname = _Bankname.InnerText
 119:                  status = _Status.InnerText
 120:                  error_code = _Error_code.InnerText
 121:                  error_comment = _Error_comment.InnerText
 122:                  packetdate = _Packetdate.InnerText
 123:                  processingname = _Processingname.InnerText
 124:                  paymenttransactiontype_id = _Paymenttransactiontype_id.InnerText
 125:              Else
 126:                  faultcode = "AssistResponse Parser error"
 127:                  faultstring = DR(1).ToString
 128:              End If
 129:          Catch ex As Exception
 130:              faultcode = "AssistResponse Parser error"
 131:              faultstring = ex.Message
 132:          End Try
 133:      End Sub
 134:  End Class
 135:   
 136:   
 137:  Partial Public Class UserDefinedFunctions
 138:      <Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName:="FillOneRow", Name:="AssistResponse", _
 139:      TableDefinition:="i int, " & _
 140:      "ordernumber Nvarchar(max), " & _
 141:      "response_code Nvarchar(max), " & _
 142:      "recommendation Nvarchar(max), " & _
 143:      "message Nvarchar(max), " & _
 144:      "comment Nvarchar(max), " & _
 145:      "date Nvarchar(max), " & _
 146:      "total Nvarchar(max), " & _
 147:      "currency Nvarchar(max), " & _
 148:      "cardtype Nvarchar(max), " & _
 149:      "cardnumber Nvarchar(max), " & _
 150:      "lastname Nvarchar(max), " & _
 151:      "firstname Nvarchar(max), " & _
 152:      "middlename Nvarchar(max), " & _
 153:      "address Nvarchar(max), " & _
 154:      "email Nvarchar(max), " & _
 155:      "country Nvarchar(max), " & _
 156:      "rate Nvarchar(max), " & _
 157:      "approvalcode Nvarchar(max), " & _
 158:      "cardsubtype Nvarchar(max), " & _
 159:      "cvc2 Nvarchar(max), " & _
 160:      "cardholder Nvarchar(max), " & _
 161:      "ipaddress Nvarchar(max), " & _
 162:      "protocoltypename Nvarchar(max), " & _
 163:      "billnumber Nvarchar(max), " & _
 164:      "bankname Nvarchar(max), " & _
 165:      "status Nvarchar(max), " & _
 166:      "error_code Nvarchar(max), " & _
 167:      "error_comment Nvarchar(max), " & _
 168:      "packetdate Nvarchar(max), " & _
 169:      "processingname Nvarchar(max), " & _
 170:      "paymenttransactiontype_id Nvarchar(max), " & _
 171:      "faultcode Nvarchar(max), " & _
 172:      "faultstring Nvarchar(max)", DataAccess:=DataAccessKind.Read)> _
 173:      Public Shared Function AssistResponse() As IEnumerable
 174:          Dim X As New Collections.Generic.List(Of OneRow)
 175:          Using CN As New SqlConnection("context connection=true")
 176:              Using CMD As SqlCommand = CN.CreateCommand()
 177:                  CMD.CommandText = "select i,AssistStatusResponseXML from dbo.Request with (nolock)"
 178:                  CN.Open()
 179:                  Using DR = CMD.ExecuteReader
 180:                      While DR.Read
 181:                          X.Add(New OneRow(DR))
 182:                      End While
 183:                      DR.Close()
 184:                  End Using
 185:              End Using
 186:              CN.Close()
 187:          End Using
 188:          Return X
 189:      End Function
 190:   
 191:      Public Shared Sub FillOneRow(ByVal row As Object, _
 192:          <Runtime.InteropServices.Out()> ByRef i As Integer, _
 193:          <Runtime.InteropServices.Out()> ByRef ordernumber As String, _
 194:          <Runtime.InteropServices.Out()> ByRef response_code As String, _
 195:          <Runtime.InteropServices.Out()> ByRef recommendation As String, _
 196:          <Runtime.InteropServices.Out()> ByRef message As String, _
 197:          <Runtime.InteropServices.Out()> ByRef comment As String, _
 198:          <Runtime.InteropServices.Out()> ByRef [date] As String, _
 199:          <Runtime.InteropServices.Out()> ByRef total As String, _
 200:          <Runtime.InteropServices.Out()> ByRef currency As String, _
 201:          <Runtime.InteropServices.Out()> ByRef cardtype As String, _
 202:          <Runtime.InteropServices.Out()> ByRef cardnumber As String, _
 203:          <Runtime.InteropServices.Out()> ByRef lastname As String, _
 204:          <Runtime.InteropServices.Out()> ByRef firstname As String, _
 205:          <Runtime.InteropServices.Out()> ByRef middlename As String, _
 206:          <Runtime.InteropServices.Out()> ByRef address As String, _
 207:          <Runtime.InteropServices.Out()> ByRef email As String, _
 208:          <Runtime.InteropServices.Out()> ByRef country As String, _
 209:          <Runtime.InteropServices.Out()> ByRef rate As String, _
 210:          <Runtime.InteropServices.Out()> ByRef approvalcode As String, _
 211:          <Runtime.InteropServices.Out()> ByRef cardsubtype As String, _
 212:          <Runtime.InteropServices.Out()> ByRef cvc2 As String, _
 213:          <Runtime.InteropServices.Out()> ByRef cardholder As String, _
 214:          <Runtime.InteropServices.Out()> ByRef ipaddress As String, _
 215:          <Runtime.InteropServices.Out()> ByRef protocoltypename As String, _
 216:          <Runtime.InteropServices.Out()> ByRef billnumber As String, _
 217:          <Runtime.InteropServices.Out()> ByRef bankname As String, _
 218:          <Runtime.InteropServices.Out()> ByRef status As String, _
 219:          <Runtime.InteropServices.Out()> ByRef error_code As String, _
 220:          <Runtime.InteropServices.Out()> ByRef error_comment As String, _
 221:          <Runtime.InteropServices.Out()> ByRef packetdate As String, _
 222:          <Runtime.InteropServices.Out()> ByRef processingname As String, _
 223:          <Runtime.InteropServices.Out()> ByRef paymenttransactiontype_id As String, _
 224:          <Runtime.InteropServices.Out()> ByRef faultcode As String, _
 225:          <Runtime.InteropServices.Out()> ByRef faultstring As String)
 226:          '
 227:          If row Is Nothing Then Exit Sub
 228:          '
 229:          Dim X As OneRow = CType(row, OneRow)
 230:          '
 231:          i = X.i
 232:          ordernumber = X.ordernumber
 233:          response_code = X.response_code
 234:          recommendation = X.recommendation
 235:          message = X.message
 236:          comment = X.comment
 237:          [date] = X.[date]
 238:          total = X.total
 239:          currency = X.currency
 240:          cardtype = X.cardtype
 241:          cardnumber = X.cardnumber
 242:          lastname = X.lastname
 243:          firstname = X.firstname
 244:          middlename = X.middlename
 245:          address = X.address
 246:          email = X.email
 247:          country = X.country
 248:          rate = X.rate
 249:          approvalcode = X.approvalcode
 250:          cardsubtype = X.cardsubtype
 251:          cvc2 = X.cvc2
 252:          cardholder = X.cardholder
 253:          ipaddress = X.ipaddress
 254:          protocoltypename = X.protocoltypename
 255:          billnumber = X.billnumber
 256:          bankname = X.bankname
 257:          status = X.status
 258:          error_code = X.error_code
 259:          error_comment = X.error_comment
 260:          packetdate = X.packetdate
 261:          processingname = X.processingname
 262:          paymenttransactiontype_id = X.paymenttransactiontype_id
 263:          faultcode = X.faultcode
 264:          faultstring = X.faultstring
 265:      End Sub
 266:  End Class
 267:   
 268:   
 269:  Public Class ParceNamespace
 270:   
 271:      Dim _XML As New System.Xml.XmlDocument
 272:      Public ReadOnly Property XML() As System.Xml.XmlDocument
 273:          Get
 274:              Return _XML
 275:          End Get
 276:      End Property
 277:   
 278:      Dim _NamespaceManager As System.Xml.XmlNamespaceManager
 279:      Public ReadOnly Property NamespaceManager() As System.Xml.XmlNamespaceManager
 280:          Get
 281:              Return _NamespaceManager
 282:          End Get
 283:      End Property
 284:   
 285:   
 286:      Public Sub New(ByVal ResponseXML As String)
 287:          _XML.LoadXml(ResponseXML)
 288:          Dim AllNameSpace As New System.Collections.Specialized.NameValueCollection
 289:          For I As Integer = 1 To 20
 290:              Dim XpatchBuilder As New System.Text.StringBuilder
 291:              XpatchBuilder.Append("/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*", 0, I * 2)
 292:              Dim CurrentNodeList As System.Xml.XmlNodeList = _XML.SelectNodes(XpatchBuilder.ToString)
 293:              If CurrentNodeList IsNot Nothing Then
 294:                  If CurrentNodeList.Count > 0 Then
 295:                      For Each CurrentNode As System.Xml.XmlNode In CurrentNodeList
 296:                          If CurrentNode.Attributes IsNot Nothing Then
 297:                              If CurrentNode.Attributes.Count > 0 Then
 298:                                  For Each CurrentAttr As System.Xml.XmlAttribute In CurrentNode.Attributes
 299:                                      If CurrentAttr.Prefix = "xmlns" Then
 300:                                          AllNameSpace.Add(CurrentAttr.LocalName, CurrentAttr.Value)
 301:                                      End If
 302:                                  Next
 303:                              End If
 304:                          End If
 305:                      Next
 306:                  Else
 307:                      Exit For
 308:                  End If
 309:              End If
 310:          Next
 311:          For i As Integer = 0 To AllNameSpace.Count - 1
 312:              _XML.NameTable.Add(AllNameSpace.Keys(i))
 313:          Next
 314:          _NamespaceManager = New System.Xml.XmlNamespaceManager(_XML.NameTable)
 315:          For i As Integer = 0 To AllNameSpace.Count - 1
 316:              _NamespaceManager.AddNamespace(AllNameSpace.Keys(i), AllNameSpace.Get(i))
 317:          Next
 318:      End Sub
 319:   
 320:  End Class

Как видите, табличная сборка вполне тривиальна. Функция AssistResponse (137-189) читает из базы XML, декларирует формат выходной таблички и обьявляет что имя функции, заполняющей каждую строку таблички - FillOneRow.

Класс OneRow (7-134) готовит данные для одной строки нашей таблички, которая должна получиться в итоге вызова сборки. А сама функция FillOneRow (191-266) в нашем случае получается тупо заглушкой, которая копирует данные из класса OneRow в созданную в строке 181 каждую новую строку таблички.

Небольшая хитрость, до которой так и не сумели додуматься в гавнософте - это сбор и автоматическое добавление всех существующих в SOAP неймспейсов. Это я делаю в строках 269-320. И непосредственно перед вызовом XPATH-выражений, с помощью которых я выковыриваю из XML данные (53-54,62-92) я автоматически собираю неймспейсы по XML cвоим сервисом. В итоге я могу тупо копировать XPATH например из Альтовы, не заморачиваясь каждый раз - а какой же мне сейчас нужен NamespaceManager для этого отбора?

Ну вот собственно и все. Надеюсь после этой моей публикации ни задачка парсинга SOAP внутри MS SQL, ни задача коллекционирования Namespace по XML уже ни у кого проблем вызывать не будет.



Comments ( )
Link to this page: //www.vb-net.com/Sql-SOAP/index.htm
< THANKS ME>