I'm using JsonConvert SerializeXmlNode to convert xml to json. The problem that I'm facing with is that I have a tag which sometimes can have value and sometimes be null
<AustrittDatum>2018-01-31+01:00</AustrittDatum>
...
<AustrittDatum xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
And as result - I'm getting an exception when trying to deserialize json to C# object with string property "AustrittDatum" - "Newtonsoft.Json.JsonReaderException: 'Error reading string. Unexpected token: StartObject. Path 'AustrittDatum'.' ", because
<AustrittDatum xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance xsi:nil="true"/>
is serialized to
"AustrittDatum": {
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"@xsi:nil": "true"
},
How can I force it to be something like this "AustrittDatum": ""
or maybe ther is some proper way to resolve it?
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.
C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.
What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.
It seems as though, when encountering an XML element with xsi:nil="true"
, Json.NET's XmlNodeConverter
creates a JSON object with the attributes you see rather than a null JToken
. This is consistent with the Newtonsoft documentation page Converting between JSON and XML:
Converstion Rules
- Elements remain unchanged.
- Attributes are prefixed with an @ and should be at the start of the object.
- Single child text nodes are a value directly against an element, otherwise they are accessed via #text.
- The XML declaration and processing instructions are prefixed with ?.
- Character data, comments, whitespace and significant whitespace nodes are accessed via #cdata-section, #comment, #whitespace and #significant-whitespace respectively.
- Multiple nodes with the same name at the same level are grouped together into an array.
- Empty elements are null.
If the XML created from JSON doesn't match what you want, then you will need to convert it manually...
Nevertheless it's reasonable to think that an element with xsi:nil="true"
would be converted to a null
JSON value, since xsi:nil
is a predefined w3c attribute. Possibly Newtonsoft did not do this because such elements can carry additional attributes, which would be lost if the element were to be converted to null.
You could file an enhancement request for XmlNodeConverter
if you like, but in the meantime the following extension methods will post-process a JToken
hierarchy and convert objects that were formerly nil
elements to null JSON values:
public static class JTokenExtensions
{
const string XsiNamespace = @"http://www.w3.org/2001/XMLSchema-instance";
readonly static string XmlNullValue = System.Xml.XmlConvert.ToString(true);
public static JToken ReplaceXmlNilObjectsWithNull(this JToken root)
{
return root.ReplaceXmlNilObjects(t => JValue.CreateNull());
}
public static JToken ReplaceXmlNilObjects(this JToken root, Func<JToken, JToken> getReplacement)
{
var query = from obj in root.DescendantsAndSelf().OfType<JObject>()
where obj.Properties().Any(p => p.IsNilXmlTrueProperty())
select obj;
foreach (var obj in query.ToList())
{
var replacement = getReplacement(obj);
if (obj == root)
root = replacement;
if (obj.Parent != null)
obj.Replace(replacement);
}
return root;
}
static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
{
// Small wrapper adding this method to all JToken types.
if (node == null)
return Enumerable.Empty<JToken>();
var container = node as JContainer;
if (container != null)
return container.DescendantsAndSelf();
else
return new[] { node };
}
static string GetXmlNamespace(this JProperty prop)
{
if (!prop.Name.StartsWith("@"))
return null;
var index = prop.Name.IndexOf(":");
if (index < 0 || prop.Name.IndexOf(":", index+1) >= 0)
return null;
var ns = prop.Name.Substring(1, index - 1);
if (string.IsNullOrEmpty(ns))
return null;
var nsPropertyName = "@xmlns:" + ns;
foreach (var obj in prop.AncestorsAndSelf().OfType<JObject>())
{
var nsProperty = obj[nsPropertyName];
if (nsProperty != null && nsProperty.Type == JTokenType.String)
return (string)nsProperty;
}
return null;
}
static bool IsNilXmlTrueProperty(this JProperty prop)
{
if (prop == null)
return false;
if (!(prop.Value.Type == JTokenType.String && (string)prop.Value == "true"))
return false;
if (!(prop.Name.StartsWith("@") && prop.Name.EndsWith(":nil")))
return false;
var ns = prop.GetXmlNamespace();
return ns == XsiNamespace;
}
}
Then use it like:
// Parse XML to XDocument
var xDoc = XDocument.Parse(xmlString);
// Convert the XDocument to an intermediate JToken hierarchy.
var converter = new Newtonsoft.Json.Converters.XmlNodeConverter { OmitRootObject = true };
var rootToken = JObject.FromObject(xDoc, JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = { converter } } ))
// And replace xsi:nil objects will null JSON values
.ReplaceXmlNilObjectsWithNull();
// Deserialize to the final RootObject.
var rootObject = rootToken.ToObject<RootObject>();
Which generates:
"AustrittDatum": [
"2018-01-31+01:00",
null
],
Here I am initially parsing to an XDocument
but you could also use the older XmlDocument
Sample working .Net fiddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With