如何让Delphi Alexandria SOAP客户端不再生成xsi:nil="true"元素
问题描述
自Delphi Alexandria 11.2版本起,SOAP客户端出现异常行为:当客户端对象的obj.entryDate字段设为nil(无对应日期时),Delphi SOAP库生成的请求会包含该元素的xsi:nil="true"声明。但对应的WSDL中该元素标记为可选(minOccurs="0"),导致Java WebService无法解析请求,返回解组错误。
WSDL片段
<xs:complexType name="baseArchivDokumentDTO"> <xs:sequence> <xs:element name="entryDate" type="xs:dateTime" minOccurs="0"/> </xs:sequence> </xs:complexType>
生成的错误SOAP请求
<arg0> <test>1</test> <entryDate xsi:nil="true"/> </arg0>
Java服务返回的错误响应
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault> <faultcode>soap:Client</faultcode> <faultstring>Unmarshalling Error:</faultstring> </soap:Fault> </soap:Body> </soap:Envelope>
期望的正常请求
<arg0> <test>1</test> </arg0>
解决方案
以下三种方法可恢复旧版本的正常行为:
1. 修改生成的DTO类代码
在WSDL生成的baseArchivDokumentDTO类中,调整entryDate属性的存储逻辑,确保字段为nil时不被序列化:
- 找到属性定义代码:
property entryDate: TXSDateTime read FentryDate write SetentryDate stored IsentryDateStored; - 若生成代码中无
IsentryDateStored方法,手动添加:function TbaseArchivDokumentDTO.IsentryDateStored: Boolean; begin Result := FentryDate <> nil; end;
该方法会在序列化时判断,当entryDate为nil时跳过该元素。
2. 调整SOAP客户端全局选项
创建SOAP客户端实例时,移除soSendEmptyParamAsNil选项,阻止空参数被序列化为xsi:nil="true":
Client := TYourSOAPClient.Create(nil); Client.SOAPOptions := Client.SOAPOptions - [soSendEmptyParamAsNil];
3. 自定义序列化前处理逻辑
绑定客户端的OnBeforeSerialize事件,手动移除带xsi:nil="true"的元素:
procedure TYourForm.ClientBeforeSerialize(Sender: TObject; const SOAPObject: TObject; var XMLNode: IXMLNode); var EntryDateNode: IXMLNode; begin EntryDateNode := XMLNode.ChildNodes.FindNode('entryDate'); if Assigned(EntryDateNode) and (EntryDateNode.Attributes['xsi:nil'] = 'true') then XMLNode.ChildNodes.Remove(EntryDateNode); end;
将客户端的OnBeforeSerialize事件指向上述方法即可。
内容的提问来源于stack exchange,提问作者Markus
相关产品推荐
相关产品推荐

