我正在尝试开发一个可以通过OPC XML-DA规范访问数据的soap客户端:Here
我使用了gSOAP提供的工具从OPC Foundations WSDL生成gSOAP头文件。 (以下相关部分)
我似乎无法让gSOAP正确地向标签添加属性。 (参见下面的输出部分)。是否有内置的方法来执行此操作,还是需要修改WSDL / gSOAP标头?
WSDL提取:
<s:complexType name="ItemValue">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="DiagnosticInfo" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Value" />
<s:element minOccurs="0" maxOccurs="1" name="Quality" type="s0:OPCQuality" />
</s:sequence>
<s:attribute name="ValueTypeQualifier" type="s:QName" />
<s:attribute name="ItemPath" type="s:string" />
<s:attribute name="ItemName" type="s:string" />
<s:attribute name="ClientItemHandle" type="s:string" />
<s:attribute name="Timestamp" type="s:dateTime" />
<s:attribute name="ResultID" type="s:QName" />
</s:complexType>
生成的gSOAP标题
class ns1__ItemValue
{ public:
/// Element DiagnosticInfo of type xs:string.
char* DiagnosticInfo 0; ///< Optional element.
/// Element 'Value' has no type or ref: assuming XML content.
_XML Value 0; ///< Optional element.
/// Element Quality of type "http://opcfoundation.org/webservices/XMLDA/1.0/":OPCQuality.
ns1__OPCQuality* Quality 0; ///< Optional element.
/// Attribute ValueTypeQualifier of type xs:QName.
@_QName ValueTypeQualifier 0; ///< Optional attribute.
/// Attribute ItemPath of type xs:string.
@char* ItemPath 0; ///< Optional attribute.
/// Attribute ItemName of type xs:string.
@char* ItemName 0; ///< Optional attribute.
/// Attribute ClientItemHandle of type xs:string.
@char* ClientItemHandle 0; ///< Optional attribute.
/// Attribute Timestamp of type xs:dateTime.
@time_t* Timestamp 0; ///< Optional attribute.
/// Attribute ResultID of type xs:QName.
@_QName ResultID 0; ///< Optional attribute.
/// A handle to the soap struct that manages this instance (automatically set)
struct soap *soap ;
};
生成代码
class SOAP_CMAC ns1__ItemValue
{
public:
char *DiagnosticInfo; /* optional element of type xsd:string */
char *Value; /* optional element of type xsd:anyType */
class ns1__OPCQuality *Quality; /* optional element of type ns1:OPCQuality */
char *ValueTypeQualifier; /* optional attribute */
char *ItemPath; /* optional attribute */
char *ItemName; /* optional attribute */
char *ClientItemHandle; /* optional attribute */
time_t *Timestamp; /* optional attribute */
char *ResultID; /* optional attribute */
struct soap *soap; /* transient */
public:
virtual int soap_type() const { return 18; } /* = unique id SOAP_TYPE_ns1__ItemValue */
virtual void soap_default(struct soap*);
virtual void soap_serialize(struct soap*) const;
virtual int soap_put(struct soap*, const char*, const char*) const;
virtual int soap_out(struct soap*, const char*, int, const char*) const;
virtual void *soap_get(struct soap*, const char*, const char*);
virtual void *soap_in(struct soap*, const char*, const char*);
ns1__ItemValue() : DiagnosticInfo(NULL), Value(NULL), Quality(NULL), ValueTypeQualifier(NULL), ItemPath(NULL), ItemName(NULL), ClientItemHandle(NULL), Timestamp(NULL), ResultID(NULL), soap(NULL) { }
virtual ~ns1__ItemValue() { }
};
输出
<ns1:Items
ClientItemHandle="Channel1.Device1"
ItemName="Channel_1.Device_1.Tag_1"
ValueTypeQualifier="xsd:unsignedInt">
<Value
xmlns="http://opcfoundation.org/webservices/XMLDA/1.0/">
5
</Value>
</ns1:Items>
需要的输出
<ns1:Items
ClientItemHandle="Channel1.Device1"
ItemName="Channel_1.Device_1.Tag_1"
ValueTypeQualifier="xsd:unsignedInt">
<Value
xmlns="http://opcfoundation.org/webservices/XMLDA/1.0/"
xsi:Type="xsd:unsignedInt">
5
</Value>
</ns1:Items>
输出表示通过网络生成并发送到远程服务器的XML。
答案 0 :(得分:1)
这可能会有所帮助。我现在无法测试它,所以这只是一个建议。看看'Void指针':http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc11.9
struct myStruct
{
int __type; // the SOAP_TYPE pointed to by p
void *p;
};
据我从文档中了解,这用于序列化任何东西,并指定它的类型。 因此,使用此结构替换Value元素的_XML类型可能会有效。 然后,您只需使用相应的值设置__type属性:
struct ns1_Value {
int __type; // the SOAP_TYPE pointed to by p
void *p;
}
struct ns1_Value value;
int n;
value.p = &n;
value.__type = SOAP_TYPE_int;
解决问题的另一种方法可能是序列化原始xml而不是&lt; Value&gt; element ...或者想到一些xs:扩展xs:anyType的元素,但是定义了一个xs:type .. 实际上gSoap是一款很酷的产品,但为了充分利用它,你需要学习如何破解它。
答案 1 :(得分:1)
@Tisho,谢谢你的意见。
事实证明,OPC Foundation提供的WSDL缺少在value元素上指定类型。我们的解决方案是添加一种s:anyType,这允许我们使用多态类型,例如:
xsd_ unsignedInt的
XSD _string
xsd__anyType
由于包含了从xsd__anyType继承的所有类型以及虚拟soap_type函数,我们可以使用任何类型,并将它们存储在值中,然后gSOAP神奇地使用soap_type来确定var的类型。
OPC Foundation的WSDL修改版的相关部分:
<s:complexType name="ItemValue">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="DiagnosticInfo" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="Value" type="s:anyType"/> <!-- Here -->
<s:element minOccurs="0" maxOccurs="1" name="Quality" type="s0:OPCQuality"/>
</s:sequence>
<s:attribute name="ValueTypeQualifier" type="s:QName"/>
<s:attribute name="ItemPath" type="s:string"/>
<s:attribute name="ItemName" type="s:string"/>
<s:attribute name="ClientItemHandle" type="s:string"/>
<s:attribute name="Timestamp" type="s:dateTime"/>
<s:attribute name="ResultID" type="s:QName"/>
</s:complexType>
这是新的gSOAP生成标题
class ns1__ItemValue : public xsd__anyType
{ public:
/// Element DiagnosticInfo of type xs:string.
char* DiagnosticInfo 0; ///< Optional element.
/// Element Value of type xs:anyType.
xsd__anyType* Value 0; ///< Optional element.
/// Element Quality of type "http://opcfoundation.org/webservices/XMLDA/1.0/":OPCQuality.
ns1__OPCQuality* Quality 0; ///< Optional element.
/// Attribute ValueTypeQualifier of type xs:QName.
@_QName ValueTypeQualifier 0; ///< Optional attribute.
/// Attribute ItemPath of type xs:string.
@char* ItemPath 0; ///< Optional attribute.
/// Attribute ItemName of type xs:string.
@char* ItemName 0; ///< Optional attribute.
/// Attribute ClientItemHandle of type xs:string.
@char* ClientItemHandle 0; ///< Optional attribute.
/// Attribute Timestamp of type xs:dateTime.
@time_t* Timestamp 0; ///< Optional attribute.
/// Attribute ResultID of type xs:QName.
@_QName ResultID 0; ///< Optional attribute.
};