Как парсить 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 уже ни у кого проблем вызывать не будет.
|