diff --git a/async-opcua-macros/src/encoding/xml.rs b/async-opcua-macros/src/encoding/xml.rs index 2a52be04..9b680feb 100644 --- a/async-opcua-macros/src/encoding/xml.rs +++ b/async-opcua-macros/src/encoding/xml.rs @@ -102,12 +102,16 @@ pub fn generate_xml_encode_impl(strct: EncodingStruct) -> syn::Result bool { + self.is_null() + } } impl XmlDecodable for ExpandedNodeId { diff --git a/async-opcua-types/src/node_id.rs b/async-opcua-types/src/node_id.rs index eda0a659..d9fd32f3 100644 --- a/async-opcua-types/src/node_id.rs +++ b/async-opcua-types/src/node_id.rs @@ -357,6 +357,10 @@ mod xml { let val = ctx.resolve_alias_inverse(&self_str); writer.encode_child("Identifier", val, ctx) } + + fn is_null_xml(&self) -> bool { + self.is_null() + } } impl XmlDecodable for NodeId { diff --git a/async-opcua-types/src/qualified_name.rs b/async-opcua-types/src/qualified_name.rs index c88048a3..6273758a 100644 --- a/async-opcua-types/src/qualified_name.rs +++ b/async-opcua-types/src/qualified_name.rs @@ -67,6 +67,10 @@ mod xml { writer.encode_child("Name", &self.name, context)?; Ok(()) } + + fn is_null_xml(&self) -> bool { + self.is_null() + } } impl XmlDecodable for QualifiedName { diff --git a/async-opcua-types/src/string.rs b/async-opcua-types/src/string.rs index 3ae97784..82014917 100644 --- a/async-opcua-types/src/string.rs +++ b/async-opcua-types/src/string.rs @@ -159,6 +159,10 @@ mod xml { Ok(()) } + + fn is_null_xml(&self) -> bool { + self.is_null() + } } impl XmlDecodable for UAString { diff --git a/async-opcua-types/src/tests/xml.rs b/async-opcua-types/src/tests/xml.rs index 134ee529..b554a5f1 100644 --- a/async-opcua-types/src/tests/xml.rs +++ b/async-opcua-types/src/tests/xml.rs @@ -359,7 +359,7 @@ fn from_xml_variant() { &Variant::from(EUInformation { namespace_uri: "https://my.namespace.uri".into(), unit_id: 1, - display_name: LocalizedText::new("en", "MyUnit"), + display_name: LocalizedText::from("MyUnit"), description: LocalizedText::new("en", "MyDesc"), }), r#" @@ -369,7 +369,7 @@ fn from_xml_variant() { https://my.namespace.uri 1 - enMyUnit + MyUnit enMyDesc diff --git a/async-opcua-types/src/xml/builtins.rs b/async-opcua-types/src/xml/builtins.rs index 3cb93c76..7bd4cab9 100644 --- a/async-opcua-types/src/xml/builtins.rs +++ b/async-opcua-types/src/xml/builtins.rs @@ -21,6 +21,10 @@ macro_rules! xml_enc_number { writer.write_text(&self.to_string())?; Ok(()) } + + fn is_null_xml(&self) -> bool { + *self == 0 + } } impl XmlDecodable for $t { @@ -63,6 +67,10 @@ macro_rules! xml_enc_float { } Ok(()) } + + fn is_null_xml(&self) -> bool { + *self == 0.0 + } } impl XmlDecodable for $t { @@ -165,6 +173,10 @@ impl XmlEncodable for bool { writer.write_text(if *self { "true" } else { "false" })?; Ok(()) } + + fn is_null_xml(&self) -> bool { + !self + } } impl XmlType for Box @@ -200,6 +212,10 @@ where ) -> Result<(), Error> { self.as_ref().encode(writer, context) } + + fn is_null_xml(&self) -> bool { + self.as_ref().is_null_xml() + } } impl XmlType for Vec @@ -248,7 +264,11 @@ where context: &Context<'_>, ) -> super::EncodingResult<()> { for item in self { - writer.encode_child(item.tag(), item, context)?; + if item.is_null_xml() { + writer.write_empty(item.tag())?; + } else { + writer.encode_child(item.tag(), item, context)?; + } } Ok(()) } @@ -292,4 +312,8 @@ where } Ok(()) } + + fn is_null_xml(&self) -> bool { + self.is_none() + } } diff --git a/async-opcua-types/src/xml/encoding.rs b/async-opcua-types/src/xml/encoding.rs index 11417147..189fe0b3 100644 --- a/async-opcua-types/src/xml/encoding.rs +++ b/async-opcua-types/src/xml/encoding.rs @@ -55,6 +55,12 @@ pub trait XmlEncodable: XmlType { writer: &mut XmlStreamWriter<&mut dyn Write>, context: &Context<'_>, ) -> EncodingResult<()>; + + /// This method should return `true` if the value is default + /// and should not be serialized. + fn is_null_xml(&self) -> bool { + false + } } /// Extensions for XmlStreamWriter. diff --git a/async-opcua-xml/src/encoding/writer.rs b/async-opcua-xml/src/encoding/writer.rs index 30a11807..ebca6a9d 100644 --- a/async-opcua-xml/src/encoding/writer.rs +++ b/async-opcua-xml/src/encoding/writer.rs @@ -49,6 +49,13 @@ impl XmlStreamWriter { Ok(()) } + /// Write an empty tag to the stream. + pub fn write_empty(&mut self, tag: &str) -> Result<(), XmlWriteError> { + self.writer + .write_event(Event::Empty(BytesStart::new(tag)))?; + Ok(()) + } + /// Write node contents to the stream. pub fn write_text(&mut self, text: &str) -> Result<(), XmlWriteError> { self.writer.write_event(Event::Text(BytesText::new(text)))?;