Не удалось разобрать XML: ожидается пробел

У меня есть простая функция VBA, которая отправляет POST на удаленный сервер. Тело сообщения представляет собой XML-документ.

Sub testmessage()
Dim sXML As String, sURL As String, sResponse As String
Dim WinHttpReq As Object

Set WinHttpReq = CreateObject("MSXML2.ServerXMLHTTP")

sXML = "<?xml version=""1.0"" encoding=""ISO-8859-1""?>"
sXML = sXML & "<!DOCTYPE pnet_imessage_send PUBLIC ""-//PeopleNet//pnet_imessage_send"""
sXML = sXML & " ""http://open.peoplenetonline.com/dtd/pnet_imessage_send.dtd""> "
sXML = sXML & "<pnet_imessage_send>"
sXML = sXML & "  <cid>20</cid>"
sXML = sXML & "  <pw>password</pw>"
sXML = sXML & "  <vehicle_number>123</vehicle_number>"
sXML = sXML & "  <deliver>now</deliver>"
sXML = sXML & "  <freeform_message>This is Tim's test message.</freeform_message>"
sXML = sXML & "</pnet_imessage_send>"

'Test url'
'sURL = "https://open.pfmlogin.com/scripts/postp.dll"

'Live url
sURL = "https://oi.pfmlogin.com/scripts/open.dll"

WinHttpReq.Open "POST", sURL, False
WinHttpReq.setRequestHeader "Content-Type", "application/x-www-form-urlencoded;Charset=ISO-8859-1"
WinHttpReq.Send sXML
sResponse = WinHttpReq.responseText

Debug.Print sResponse
End Sub

sXML содержит это:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE pnet_imessage_send PUBLIC "-//PeopleNet//pnet_imessage_send" 
  "http://open.peoplenetonline.com/dtd/pnet_imessage_send.dtd"> 
<pnet_imessage_send>
  <cid>20</cid>
  <pw>password</pw>
  <vehicle_number>123</vehicle_number>
  <deliver>now</deliver>
  <freeform_message>This is Tim's test message.</freeform_message> 
</pnet_imessage_send>

Если я отправлю это с помощью подключаемого модуля Postman в Chrome, оно будет обработано без проблема. При публикации с кодом VBA он возвращает ошибку XML failed to parse. The reported error was: File: . Line: 1 Col: 19 Error: Whitespace expected at Line: 1 Position: 19.

Если я отправляю данные на тестовый URL-адрес (который просто возвращает все, что было отправлено на него), это выглядит так:

<?xml version="1.0"
encoding="ISO-8859-1"
><!DOCTYPE pnet_imessage_send PUBLIC "-//PeopleNet//pnet_imessage_send"
http://open.peoplenetonline.com/dtd/pnet_imessage_send.dtd

Я полагаю, что сервер не обрабатывает разрывы строк как пробелы, в результате чего парсер XML выглядит примерно так: <?xml version="1.0"encoding="ISO-8859-1"> (без пробела между "1.0" и кодировкой). Сообщения, сделанные с помощью Postman, не имеют неожиданных разрывов строк. Как я могу опубликовать эти данные, не разбивая пролог VBA?


person Tim    schedule 16.04.2018    source источник
comment
Заголовок вашего запроса имеет тип содержимого application/x-www-form-urlencoded, но вы не кодируете URL-адрес полезной нагрузки XML.   -  person Tim Williams    schedule 17.04.2018
comment
stackoverflow.com/questions/218181/   -  person Tim Williams    schedule 17.04.2018
comment
@TimWilliams, комментируя строку setRequestHeader, по-прежнему дает то же самое Error: Whitespace expected at Line: 1 Position: 19   -  person Tim    schedule 17.04.2018
comment
Вы пытались оставить заголовок как есть и URL-кодировать свой XML? Кроме того, здесь точно такая же проблема (хотя и на другой клиентской платформе) .com/questions/2908597/   -  person Tim Williams    schedule 17.04.2018
comment
Может быть, я что-то упускаю, но я не вижу, чтобы вы добавляли новые строки где-нибудь в разделе конкатенации sXML = sXML & .... Попробуйте добавить & chr(10) в точках новой строкой. Возможно, в символе 19, как говорится в сообщении об ошибке, и посмотрите, говорит ли он вам, что он ожидал пробела в индексе нового символа.   -  person chillin    schedule 17.04.2018
comment
Я бы также рекомендовал кодировать URL-адрес sXML перед использованием .send (попробуйте Application.EncodeURL(sXML)), чтобы его содержимое не было повреждено во время передачи, и при сохранении заголовка запроса application/x-www-form-urlencoded.   -  person chillin    schedule 17.04.2018
comment
@TimWilliams Чертовски хорошая находка в этом коде Delphi! Это точно такая же проблема. Я искал SO и некоторое время гуглил, прежде чем публиковать. @chilln - да, вот в чем загвоздка: я нигде не добавляю разрывы строк. Что-то в процессе отправки добавляет их для меня (это не ошибка... это функция!) Я использую Excel 2010, поэтому Application.EncodeURL мне недоступен, и я намерен портировать его на VBScript для запуска по расписанию. Задача. Я видел несколько фрагментов строк кодирования HTML/URL в других сообщениях. Я попробую.   -  person Tim    schedule 17.04.2018


Ответы (1)


Кредит за этот ответ принадлежит @TimWilliams. Найдите один из его постов и поставьте ему +1, если он вам поможет.

Как указали Хе и @Chillin, данные формы должны быть закодированы в URL-адресе (или закодированы таким образом, чтобы сохранялись пробелы... HTML-кодирование тоже могло работать, но я не пробовал). Простая установка заголовка запроса на application/xml не сохранила пробелы.

Я использовал приведенный ниже код из этого сообщения SO: Как можно Я кодирую URL-адрес строки в Excel VBA? (так что поставьте +1, если это вам помогло)

Public Function URLEncode( _
   StringVal As String, _
   Optional SpaceAsPlus As Boolean = False _
) As String

  Dim StringLen As Long: StringLen = Len(StringVal)

  If StringLen > 0 Then
    ReDim result(StringLen) As String
    Dim i As Long, CharCode As Integer
    Dim Char As String, Space As String

    If SpaceAsPlus Then Space = "+" Else Space = "%20"

    For i = 1 To StringLen
      Char = Mid$(StringVal, i, 1)
      CharCode = Asc(Char)
      Select Case CharCode
        Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
          result(i) = Char
        Case 32
          result(i) = Space
        Case 0 To 15
          result(i) = "%0" & Hex(CharCode)
        Case Else
          result(i) = "%" & Hex(CharCode)
      End Select
    Next i
    URLEncode = Join(result, "")
  End If
End Function

Затем я вызываю эту функцию после объединения моей строки sXML следующим образом:

sXML = sXML & "   <freeform_message>This is Tim's test message.</freeform_message>"
sXML = sXML & "</pnet_imessage_send>"
sXML = "service=imessage_send&xml=" & URLEncode(sXML, False)

И это работает как шарм!

person Tim    schedule 17.04.2018