2

I'm looking for a JavaScript library that can deserialize/unmarshal XML (strings or DOM) to JavaScript classes in a way similar to the .NET XmlSerializer's Deserialize method.

The functionality I'm looking for:

  1. Classes are defined as JavaScript constructor functions.
  2. Mapping between nodes and classes/properties is configurable.
  3. Deserialization result consists of instances of these classes.

For example, the following XML:

<root textAttribute='text1' numberAttribute='1' attributeToIgnore1='ignored1' attributeToIgnore2='ignored2'>
  <children>
    <child>text2</child>
    <child>text3</child>
  </children>
  <childToIgnore>ignored3</childToIgnore>
</root>

used with JavaScript definitions similar to these:

function RootClass() {
  this.stringProperty = "";
  this.integerProperty = 0;
  this.collectionProperty = [];
}

function ChildClass() {
  this.stringProperty = "";
}

should produce JavaScript objects similar to the following:

var result = new RootClass();
result.textProperty = "text1";
result.integerProperty = 1;
result.collectionProperty = [];
result.collectionProperty[0] = new ChildClass();
result.collectionProperty[0].textProperty = "text2";
result.collectionProperty[1] = new ChildClass();
result.collectionProperty[1].textProperty = "text3;

An example of .NET (C#) code that does the same would be something like (see this .NET Fiddle for a working example):

public class Program
{
    public static void Main()
    {
        var result = Serializer.Deserialize();

        Console.WriteLine("text: {0}", result.StringProperty);
        Console.WriteLine("number: {0}", result.IntegerProperty);
        Console.WriteLine("enum: {0}", result.EnumProperty);
        Console.WriteLine("child[0].Value: {0}", result.CollectionProperty[0].Value);
        Console.WriteLine("other@[0]: {0}", result.OtherAttributes[0].InnerText);
        Console.WriteLine("other*[0]: {0}", result.OtherElements[0].InnerText);
    }
}

public static class Serializer
{
    public static RootClass Deserialize()
    {
        var type = typeof (RootClass);

        var serializer = new XmlSerializer(type);

        var xmlString = @"
                <root textAttribute='text1' numberAttribute='1' enumAttribute='item1' attributeToIgnore1='ignored1' attributeToIgnore2='ignored2'>
                    <children>
                        <child>text2</child>
                        <child>text3</child>
                    </children>
                    <childToIgnore>ignored3</childToIgnore>
                </root>";

        using (var stringReader = new StringReader(xmlString))
        {
            return serializer.Deserialize(stringReader) as RootClass;
        }
    }
}

[XmlRoot("root")]
public class RootClass
{
    [XmlAttribute("textAttribute")]
    public string StringProperty;

    [XmlAttribute("numberAttribute")]
    public int IntegerProperty;

    [XmlAttribute("enumAttribute")]
    public Enumeration EnumProperty;

    [XmlAnyAttribute]
    public XmlAttribute[] OtherAttributes;

    [XmlArray("children")]
    [XmlArrayItem("child")]
    public Collection<ChildClass> CollectionProperty;

    [XmlAnyElement]
    public XmlElement[] OtherElements;
}

public enum Enumeration
{
    [XmlEnum("item1")]
    Item1,

    [XmlEnum("item2")]
    Item2
}

public class ChildClass
{
    [XmlText]
    public string Value;
}
lexicore
  • 42,748
  • 17
  • 132
  • 221
Samu Lang
  • 2,261
  • 2
  • 16
  • 32
  • Tried this ? http://stackoverflow.com/questions/1773550/xml-json-conversion-in-javascript – Srinivasan MK Aug 18 '14 at 12:13
  • @Srinivasan__ yes, but none of the libraries mentioned in that post allow using predefined JavaScript classes or ignoring specific nodes. They don't allow any kind of mapping configuration that I've seen. If they do, could you please help with explanation and examples. – Samu Lang Aug 18 '14 at 12:31

1 Answers1

3

Jsonix by Alexey Valikov (source, guide) can deserialize XML to JavaScript based on configurable mapping.


I've contributed code to support deserializing custom classes using instance factories. This will hopefully make it into the next release of Jsonix (2.0.11).


var input = "<element1 attribute1='value1' />";

var Class1 = function () {};
Class1.prototype.toString = function () {
    return this.Property1;
};

var mapping = {
    elementInfos: [{
        elementName: "element1",
        typeInfo: new Jsonix.Model.ClassInfo({
            name: "Element1",
            instanceFactory: Class1,
            propertyInfos: [
                new Jsonix.Model.AttributePropertyInfo({
                    name: "Property1",
                    attributeName: "attribute1"
                })
            ]
        })
    }]
};

var context = new Jsonix.Context([mapping]);
var unmarshaller = context.createUnmarshaller();
var result = unmarshaller.unmarshalString(input).value;

console.log(result.toString()); // logs "value1"

A longer working example on JSFiddle uses XML from question.

Samu Lang
  • 2,261
  • 2
  • 16
  • 32
  • Your feature is not released in 2.0.11. Thank you for your contribution! https://github.com/highsource/jsonix/releases/tag/2.0.11. – lexicore Aug 25 '14 at 08:19