Skip to content

Commit 2446ce8

Browse files
authored
Fix XML Encoding of Null Variant to conform to spec (#3062)
* fix XML Encoding of Null Variant to conform to spec * fix XmlEncodedValue for null variants values to be the null (same behaviour as ExtensionObject) * Update Encoder to Produce <uax:Value xsi:nil=\"true\" /> output
1 parent dc12a4b commit 2446ce8

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

Stack/Opc.Ua.Core/Types/BuiltIn/Variant.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,12 @@ private XmlElement XmlEncodedValue
778778
{
779779
get
780780
{
781+
// check for null.
782+
if (m_value == null)
783+
{
784+
return null;
785+
}
786+
781787
// create encoder.
782788
using (XmlEncoder encoder = new XmlEncoder(MessageContextExtension.CurrentContext))
783789
{

Stack/Opc.Ua.Core/Types/Encoders/XmlEncoder.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -781,9 +781,9 @@ public void WriteVariant(string fieldName, Variant value)
781781
{
782782
PushNamespace(Namespaces.OpcUaXsd);
783783

784-
m_writer.WriteStartElement("Value", Namespaces.OpcUaXsd);
785-
WriteVariantContents(value.Value, value.TypeInfo);
786-
m_writer.WriteEndElement();
784+
m_writer.WriteStartElement("Value", Namespaces.OpcUaXsd);
785+
WriteVariantContents(value.Value, value.TypeInfo);
786+
m_writer.WriteEndElement();
787787

788788
PopNamespace();
789789

@@ -1800,8 +1800,7 @@ public void WriteVariantContents(object value, TypeInfo typeInfo)
18001800
// check for null.
18011801
if (value == null)
18021802
{
1803-
m_writer.WriteStartElement("Null", Namespaces.OpcUaXsd);
1804-
m_writer.WriteEndElement();
1803+
m_writer.WriteAttributeString("nil", Namespaces.XmlSchemaInstance, "true");
18051804
return;
18061805
}
18071806

Tests/Opc.Ua.Core.Tests/Types/Encoders/XmlEncoderTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,45 @@ public void EncodeDecodeVariantMatrix()
176176
// Check decode result against input value
177177
Assert.AreEqual(actualVariant, variant);
178178
}
179+
180+
// <summary>
181+
/// Validate the encoding and decoding of the a variant that contains a null value
182+
/// </summary>
183+
[Test]
184+
public void EncodeDecodeVariantNul()
185+
{
186+
187+
var variant = Variant.Null;
188+
189+
string expected = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<uax:VariantTest xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:uax=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">\r\n <uax:Test>\r\n <uax:Value xsi:nil=\"true\" />\r\n </uax:Test>\r\n</uax:VariantTest>";
190+
191+
// Encode
192+
var context = new ServiceMessageContext();
193+
string actualXmlValue;
194+
using (IEncoder xmlEncoder = new XmlEncoder(new XmlQualifiedName("VariantTest", Namespaces.OpcUaXsd), null, context))
195+
{
196+
xmlEncoder.PushNamespace(Namespaces.OpcUaXsd);
197+
xmlEncoder.WriteVariant("Test", variant);
198+
xmlEncoder.PopNamespace();
199+
actualXmlValue = xmlEncoder.CloseAndReturnText();
200+
}
201+
202+
// Check encode result against expected XML value
203+
Assert.AreEqual(expected.Replace("\r", "").Replace("\n", ""), actualXmlValue.Replace("\r", "").Replace("\n", ""));
204+
205+
// Decode
206+
Variant actualVariant;
207+
using (XmlReader reader = XmlReader.Create(new StringReader(actualXmlValue)))
208+
{
209+
using (IDecoder xmlDecoder = new XmlDecoder(null, reader, context))
210+
{
211+
actualVariant = xmlDecoder.ReadVariant("Test");
212+
}
213+
}
214+
215+
// Check decode result against input value
216+
Assert.AreEqual(actualVariant, variant);
217+
}
179218
#endregion
180219
}
181220
}

0 commit comments

Comments
 (0)