Я пишу приложение в Delphi 2007, который использует веб-сервис. Я использовал средство импорта WSDL, чтобы сгенерировать необходимый код для общения с сервисом, но я получаю "неожиданный подэлемент (elementname)" ошибки при попытке использовать сервис.
Используя Скрипача 2, я нашел, что проблема состоит в том, что xmlns добавляется к массиву значений, отправленных в сообщении SOAP:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="..." xmlns:xsd="..." xmlns:xsi="...">
<SOAP-ENV:Body>
<Request xmlns="http://service.com/theService/">
<UserName xmlns="">user</UserName>
<Password xmlns="">pass</Password>
<List xmlns="">
<Item xmlns="http://service.com/theService/">123456</Item>
<Item xmlns="http://service.com/theService/">84547</Item>
</List>
</Request>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Если я снова посылаю сообщение, созданное Delphi в Скрипаче, изменяя xmlns для элементов Объекта к пустой строке, я больше не получаю ошибку, и сервис отвечает правильно. т.е.:
<List xmlns="">
<Item xmlns="">123456</Item>
<Item xmlns="">84547</Item>
</List>
Теперь, я могу избавиться от атрибута xmlns для элементов списка путем изменения части инициализации моего класса обслуживания от:
InvRegistry.RegisterInvokeOptions(TypeInfo(ServicePort), ioDocument);
InvRegistry.RegisterInvokeOptions(TypeInfo(ServicePort), ioLiteral);
RemClassRegistry.RegisterSerializeOptions(RequestType, [xoLiteralParam]);
кому:
InvRegistry.RegisterInvokeOptions(TypeInfo(ServicePort), ioDocument);
RemClassRegistry.RegisterSerializeOptions(RequestType, [xoHolderClass, xoLiteralParam]);
Однако это затем заставит имя элемента Запроса быть измененным на название действия SOAP по умолчанию (напр. GetInformation), который снова вызовет ошибку. Я боролся с этим для слишком длинного, любые идеи ценились бы.
Кроме того, я создал тест приложение C#, которое использует сервис, и это не имеет никаких проблем при общении с сервисом.
Я говорил с другими людьми, у которых были похожие проблемы с сериализацией в Delphi, и кажется, что нет четкого способа исправить эту проблему.
Вместо этого решение, с которым я ушел, - это прикрепить обработчик событий к событию ONBeforeeExecute объекта THTTPRIO, который отправляет сообщение SOAP, которое дает вам доступ к сериализованному сообщению SOAP в виде строки. Оттуда я только что расставил атрибут, который вызывал проблему, и теперь все работает.
Немного уродливого решения, но это работает.