PJH
PJH

Reputation: 497

Parse Java Map<string, string> from XML into C# Object

Hey Everyone have a question here about parsing some XML in C# .net 4 MVC 3.

I have a Map (HashMap) that is serialized to XML from a java app.

I need to parse this into an object on the dotnet side but can't seem to figure it out. In my research I see you can't serialize into Dictionary<string, string>.

Someone else suggested a public struct KeyValuePair<K, V> but that didn't seem to work.

Also tried an [XmlArray("mapConfig")]

One of the prerequisites is we have to use System.Xml.Serialization because we have an abstract messenger class and I would like to avoid changing that if I don't absolutely have to.

If I have to I could possiblly change the Java object if that would make this easier but would rather use the one already there if possible. If it helps the Java layer is using Xstream.

Here is a chunk of XML that is being sent from Java

<ConfigurationMap>
    <mapConfig class="hashtable">
      <entry>
        <string>Key1</string>
        <string>Value1</string>
      </entry>
      <entry>
        <string>Key2</string>
        <string>Value2</string>
      </entry>
      <entry>
        <string>Key3</string>
        <string>Value3</string>
      </entry>
      <entry>
        <string>Key4</string>
        <string>Value4</string>
      </entry>
    </mapConfig>
</ConfigurationMap>

Thanks, please let me know if you need more information. Look forward to the answers.

--UPDATE--

I thought it was apparent but I should've mentioned that the XML is coming back in the abstract message I mentioned in the form of a string. The current method uses:

XmlDocument doc = new XmlDocument();
doc.LoadXml(this.ResponseXml);
XmlElement main = doc.DocumentElement;

XmlElement cse = util.getElementsFirstChild(main, "MessagePayload");
XmlElement ccs = util.getElementsFirstChild(cse, "ReturnedObjectNameHERE");

We then deserialize the fragment using the System.Xml attributes on the model.

Here is a simple example of a Model we use with some generic properties :

[XmlRoot("list")]
public class SearchResults : List<CSearchResult>
{
    public SearchResults() { }
}

[XmlRoot("SearchResult")]
public class SearchResult
{
    [XmlElement("Id")]
    public string OrgUnitId { get; set; }

    [XmlElement("Type")]
    public Type Type { get; set; }

    [XmlElement("Name")]
    public string Name { get; set; }

    [XmlElement("Description")]
    public string Description { get; set; }
}

-- UPDATE 2 -- I was able to get some decent model binding using this model class below

[XmlRoot("ConfigurationMap")]
public class ConfigurationMap
{
    [XmlElement("mapConfig")]
    public MapConfig mapConfig { get; set; }

}

[XmlRoot("mapConfig")]
public class MapConfig
{
    [XmlArray("entry")]
    public List<string> entry { get; set; }
}

Only problem with this is the Object property mapconfig just bunches all of the entries together in one list, which makes sense given the model.

Trying to mess around with the array types to see if I can get a better result. Looking at making MapConfig an array of Entry. The I can either keep Entry a list or make Entry an array to so the object structure becomes:

MapConfig: [[key1, value1], [key2, value2], [key3, value3], [key4, value4],]

Trying to decide if this is a better structure to work with or not.

Any advice on this would be helpful as I work through this.

Thanks

Upvotes: 0

Views: 832

Answers (2)

PJH
PJH

Reputation: 497

The solution seemed to be simpler than I imagined but really was depended upon selecting the right combination of model attributes to parse correctly.

Here is the one I decided to use as it divides each entry up into its own list item.

[XmlRoot("ConfigurationMap")]
public class ConfigurationMap
{
    [XmlArray("mapConfig")]
    [XmlArrayItem("entry")]
    public List<Entry> MapConfig { get; set; }

}

[XmlRoot("entry")]
public class Entry
{
    [XmlElement("string")]
    public List<string> entry { get; set; }
}

Hopefully this helps out someone else. Thanks for the input everyone.

Upvotes: 0

retslig
retslig

Reputation: 938

You could create a class to serialize into... So run xsd.exe on the xml...

C:\>xsd test.xml
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.0.30319.17929]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'C:\test.xsd'.

C:\>xsd test.xsd /classes
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.0.30319.17929]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'C:\test.cs'.

then just use the simple c# XmlSerializer...

NewClassName object = xml.DeSerializeStringToObject<NewClassName>();

Helper Class below

public static class XmlSerializerHelper
{
    public static T DeSerializeStringToObject<T>(this string sxml)
    {
        using (XmlTextReader xreader = new XmlTextReader(new StringReader(sxml.Replace("&", "&amp;"))))
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            return (T)xs.Deserialize(xreader);
        }
    }

    public static string SerializeObjectToString(this object obj)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            XmlSerializer x = new XmlSerializer(obj.GetType());
            x.Serialize(stream, obj);
            return Encoding.Default.GetString(stream.ToArray());
        }
    }
}

Of course the the first string in the array will be the key.

Upvotes: 2

Related Questions