从SOAP请求中删除命名空间

Wim*_*ink 10 java delphi soap delphi-2007 visual-studio-2010

我已导入WSDL并使用它来发送SOAP请求.它看起来像这样:

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <SOAP-ENV:Body>
        <Calculate xmlns="urn:xx.WSDL.xxxxxWebService">
            <ContractdocumentIn>
                <AL>
                ...More XML...
Run Code Online (Sandbox Code Playgroud)

问题是xmlns="urn:xx.WSDL.xxxxxWebService"Calculate元素中的部分.Web服务无法接受此操作.Web服务不喜欢这样的命名空间...
使用SoapUI我发现这个请求工作正常:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:col="http://example.com.service.xxx/">
    <SOAP-ENV:Body>
        <col:Calculate>
            <ContractdocumentIn>
                <AL>
                    ...More XML...
Run Code Online (Sandbox Code Playgroud)

那么,如何将请求从第一个版本更改为第二个版本?(不使用肮脏的技巧!)
(如果这会导致正确的请求格式,重新导入不是问题.)




再次:不允许任何肮脏的技巧,比如黑客攻击请求流来修改它!


虽然我还没有完全测试过,但似乎C#/ VS2010和Delphi 2010也无法使用我想要调用的Web服务.一个似乎是用Java编写的Web服务.SoapUI恰好用Java编写,因此我们有一个Java客户端与Java服务通信,这似乎工作得很好.但任何其他客户?
无论如何,还有时间添加两个标签:"Java",因为它是一个Java服务,而"vs2010"因为.NET也不喜欢这个服务.
我正准备在.NET中编写一个包含此服务的包装器,希望这样可行......但事实并非如此.所以这是一个非常严重的缺陷,可能是Java漏洞......

Bru*_*auB 14

如果服务期望:

  <col:Calculate>
     <ContractdocumentIn>
         <AL>
Run Code Online (Sandbox Code Playgroud)

和Delphi SOAP正在发送......

    <Calculate xmlns="urn:xx.WSDL.xxxxxWebService">
        <ContractdocumentIn>
            <AL>
Run Code Online (Sandbox Code Playgroud)

...问题是ContractdocumentIn是一个不合格的元素,并且(直到Delphi XE)Delphi SOAP不支持作为操作的顶级元素的非限定元素.顶级元素是函数的参数,并且无处存储底层元素必须不合格的事实; 对于映射到属性的元素,我们使用属性的索引来存储IS_UNQL标志.

顺便说一句,没有必要使用前缀.该服务将(也应)接受:

    <Calculate xmlns="urn:xx.WSDL.xxxxxWebService">
        <ContractdocumentIn xmlns="">
            <AL>
Run Code Online (Sandbox Code Playgroud)

后者更冗长,但它等同于前缀情况.

在Delphi XE中,导入器存储特定参数映射到非限定元素的事实,并且运行时对此信息起作用.我最近在一个帖子中发布了基于新闻组中D2010和D2007的XE实现的补丁:

https://forums.embarcadero.com/thread.jspa?threadID=43057

如果有人需要访问它们(它们在附件区域但可能已滚动),请给我发电子邮件,我会让它们可用.[babetet at embarcadero dot com]

干杯,

布诺

  • 是的,它应该.我发布的补丁在这里:https://forums.embarcadero.com/thread.jspa?messageID = 290788 (4认同)

Wim*_*ink 8

我的天啊!它花了很多咖啡和大量的睡眠堕落,但我设法解决了我的问题!这也很简单......
首先我按预期导入WSDL.这将生成几个TRemotable类.然后,对于需要不同命名空间的每个TRemotable,我重写ObjectToSOAP()方法!(并将XMLIntf包含在WSDL源代码中.)在我的例子中,对于几种远程类型使用这样的代码:

function AL2.ObjectToSOAP( RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString ): IXMLNode;
begin
  Result := inherited ObjectToSOAP( RootNode, ParentNode, ObjConverter, NodeName, '', '', ObjConvOpts, RefID );
end;
Run Code Online (Sandbox Code Playgroud)

哪个在Delphi XE中有效.在Delphi 2007中,我必须在输入类型上使用单元XMLIntf和XMLDoc以及此代码:

function ContractdocumentInType.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const Name, URI: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode;

  procedure AlterChildren(Child: IXMLNode);
  var
    I: Integer;
  begin
    if (Child.NodeType = ntElement) then Child.SetAttributeNS('xmlns', '', '');
    for I := 0 to Pred(Child.ChildNodes.Count) do
      AlterChildren(Child.ChildNodes[I]);
  end;

begin
  Result := inherited ObjectToSOAP(RootNode, ParentNode, ObjConverter, Name, '', ObjConvOpts, RefID);
  AlterChildren(Result);
end;
Run Code Online (Sandbox Code Playgroud)

在我看来,这是一个黑客攻击.但它并不是一个非常脏的.这是一个尝试,捕获SOAP请求和响应以检查其内容并查看它是否使用正确的命名空间.不幸的是,Delphi XE在这方面做得比Delphi 2007好得多.

不过,我保持这个Q开放的任何更好的解决方案......


顺便说一句,要添加col:到输出,我也不得不改变这一行的WSDL RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'Calculate');这样:RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'cal:Calculate');.结果就变成了<cal:Calculate xmlns:cal="http://example.webservice/">.但是,需要完成更多的事情:将其移动xmlns:cal到xml标头.但就像现在一样,它对我有用.


另一个注意事项:对于WSDL,我使用了以下设置:'One Outparam is return','Unwind literal params','Generate destructors','Warning comments',' emit literal types ','Map string to widestring'.其他选项包括:'生成有关类型和接口的详细信息','使用HTTP绑定忽略端口类​​型','验证枚举成员','导入错误类型','导入标题类型','处理包含和导入的模式','生成class alias as class types','Allow Out parameters'和'Process nillable and optional elements'.在发出的文字类型是实用的,因为它围绕我调用的单个方法生成一个类.遗憾的是,这也无济于事,尽管该类可以帮助您通过重写ObjectToSOAP()方法来修改信封中较高层的SOAP请求.
信封本身的创建在SOAPEnv单元中,它在OPToSOAPDomConv单元中使用.不幸的是,我还没有找到一种简单的方法来访问信封本身来改变标题以添加这个额外的命名空间.然后,我可以使用我自己的版本覆盖TSOAPDomConv类,该版本添加了额外的命名空间.但是代码现在正在为我工​​作,正如我父亲告诉我的那样,当他学会我编程时:永远不要修复任何没有破坏的东西.