9

I have a piece of XML that looks like

<person xmlns:json='http://james.newtonking.com/projects/json' id='1'>
   <name>Alan</name>
   <url>http://www.google.com</url>
   <role json:Array='true'>Admin</role>
</person>

When I try to serialize it to json string json = JsonConvert.SerializeXmlNode(xml); it ignores namespaces

 {
  "person": {
    "@id": "1",
    "name": "Alan",
    "url": "http://www.google.com",
    "role": [
      "Admin"
    ]
  }
}

and when I deserialize it back to xml XmlDocument xml = JsonConvert.DeserializeXmlNode(json), I get the following:

<person id='1'>
 <name>Alan</name>
  <url>http://www.google.com</url>
  <role>Admin</role>
</person>

How can I keep the json:Array attributes?

5
  • 1
    @Alok Not a single answer to my question was found in that question, only the title is relevant. Commented Feb 13, 2018 at 9:51
  • Could you also include the json data that gets converted from XMl in there? Commented Feb 13, 2018 at 9:59
  • I'm not sure it is helpful, that is the only page I have found: newtonsoft.com/json/help/html/ConvertingJSONandXML.htm Commented Feb 13, 2018 at 10:13
  • I don't see the attribute "Id" being populated in the XML when doing JSON to XML Commented Feb 13, 2018 at 10:26
  • Where is the value of the variable xml? Try checking out this newtonsoft.com/json/help/html/CustomJsonConverter.htm. This answer specifically states you need an @ sign in front of your xml variable string being set. Your code example does not show how you are reading the xml into your variable. Commented Feb 22, 2018 at 14:48

4 Answers 4

7
+50

There is overload of DeserializeXmlNode which accepts boolean flag named writeArrayAttribute. That's what you need:

XmlDocument xml = JsonConvert.DeserializeXmlNode(json, null, true);

Produces:

<person id="1">
    <name>Alan</name>
    <url>http://www.google.com</url>
    <role xmlns:json="http://james.newtonking.com/projects/json" json:Array="true">Admin</role>
</person>

Which is semantically identical to original xml.

Sign up to request clarification or add additional context in comments.

Comments

2

The XMl to JSon loses all the information of any attributes that have ':' (colon) in their name. Which is why 'id' get serialised to @id but 'xmlns:json' is lost in translation.

If you have access to the raw XML then I will suggest you replace the colons(:) by hyphens(-). In this case, the XML will be:

<person xmlns-json='http://james.newtonking.com/projects/json' id='1'>
    <name>Alan</name>
    <url>http://www.google.com</url>
    <role json-Array='true'>Admin</role>
</person>

I have checked that this serialises and de-serialises to the same input and output.

var xmlString = @"<person xmlns-json='http://james.newtonking.com/projects/json' id='1'><name>Alan</name><url>http://www.google.com</url><role json-Array='true'>Admin</role></person>";
var xml = new XmlDocument();
xml.LoadXml(xmlString);

var json = JsonConvert.SerializeXmlNode(xml);

var xmlDeserialized = JsonConvert.DeserializeXmlNode(json);
xmlDeserialized.Should().NotBeNull();
xmlDeserialized.ShouldBeEquivalentTo(xml); //All good

Comments

1

Maybe the problem is not how you serialize the xml node. Verify how you read your xml file before serializing it. Can you show us?

1 Comment

Thank you for suggestion @MickyD
1

this may be another approach custom json converter a bit long but I think it's more useful

Code

public class CustomXmlToJsonConverter : JsonConverter
    {
        private readonly Type[] _types;

        public CustomXmlToJsonConverter(params Type[] types)
        {
            _types = types;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken t = JToken.FromObject(value);

            if (t.Type != JTokenType.Object)
            {
                t.WriteTo(writer);
            }
            else
            {
                JObject o = (JObject)t;
                IList<string> propertyNames = o.Properties().Select(p => p.Name).ToList();

                o.AddFirst(new JProperty("Keys", new JArray(propertyNames)));

                o.WriteTo(writer);
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }

        public override bool CanRead
        {
            get { return false; }
        }

        public override bool CanConvert(Type objectType)
        {
            return _types.Any(t => t == objectType);
        }
    }

Usage

 string json = JsonConvert.SerializeObject(root,Formatting.Indented,new CustomXmlToJsonConverter(typeof(XElement)));

Result

{
  "Keys": [
    "person"
  ],
  "person": {
    "@json": "http://james.newtonking.com/projects/json",
    "@id": "1",
    "name": "Alan",
    "url": "http://www.google.com",
    "role": {
      "@Array": "true",
      "#text": "Admin"
    }
  }
}

Sample Data

 XNamespace jsonPrefix1 = "xmlns";
 XNamespace jsonPrefix2 = "json";
 XElement root = new XElement("person",
 new XAttribute(jsonPrefix1 + "json", "http://james.newtonking.com/projects/json"),              
new XAttribute("id","1"),
new XElement("name", "Alan"), new XElement("url", "http://www.google.com"),
new XElement("role" ,"Admin", new XAttribute(jsonPrefix2 + "Array", "true"))
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.