2

I have an XML file with the follow in it:

<tooltip>
    <text>My Tool Tip</text>
    <color>#000000</color>
    <crosshairs>
        <width>3</width>
        <color>green</color>
        <padding>5px</padding>
    </crosshairs>
    <crosshairs>
        <width>3</width>
        <color>blue</color>
    </crosshairs>
</tooltip>

I wish to load the "crosshairs" elements into a C# object - the object is then serialized out to a JSON file:

ToolTipClass toolTip = new ToolTipClass(xmlDoc);
JavaScriptSerializer s = new JavaScriptSerializer();
string aJSON = s.Serialize(toolTip);
// aJSON is now written out to file.

I do have a "toolTip" class with some public variables which are set by default in the constructor. The constuctor also reads the XML file in and overwrites the public variables with the value in the XML (e.g. is written into "public string text;", but the "crosshairs" part of the tool tip can contain either 1 or several elements - I don't want to define a class for the crosshairs as the tags within the crosshairs can be more than just the 2 defined above (width, color). eg (padding, margin, fontSize etc.)

the JSon output would look something like this:

tooltip: {
    text: "My Tool Tip",
    color: "#000000",
    crosshairs: [{
        width: 3,
        color: 'green',
        padding: '5px'
    }, {
        width: 3,
        color: 'blue'
    }]
}

What I need to know is How do I load the crosshairs elements into an object that isn't predefiend?

I have looked at: http://danielwylie.me/blog/2010/04/26/c-convert-xml-to-an-object-or-list-of-an-object/?Focus=Yes but this uses a "person" class which is not what I wanted.

Many thanks for any help/pointers.


Extra: ToolTip Class:

public class ToolTip
{
    public string backgroundColor = "rgba(255, 255, 255, .80)";
    public string borderColor = "#764D9B";
    public int borderRadius = 5;
    public int borderWidth = 1;
    //public string crosshairs = null;
    //public List<object> crosshairs = new List<object>();
    public Boolean enabled = true;
    //formatter: ;
    public Boolean shadow = true;
    public Boolean shared = false;
    public float snap = 10;
    public HCCSS style = new HCCSS();
    public string text = "[undefined]";
    public string color = "#000000";

public HCToolTip(XmlDocument xmlDoc) {
    text = findTagInXML_String(xmlDoc, "//tooltip/text", text);
    color = findTagInXML_String(xmlDoc, "//tooltip/color", color);
    //snip
}

static private string findTagInXML_String(XmlDocument xmlDoc, string tag, string defaultvalue) {
    return xmlDoc.SelectSingleNode(tag) == null || xmlDoc.SelectSingleNode(tag).InnerText == "null" ? defaultvalue : xmlDoc.SelectSingleNode(tag).InnerText;
}
}

update / reply ## (not sure how to do replies below).

Thanks for the code and the link to the converter site. I've added in some code and sort of got it doing something, but I do have a few more problems.

  1. How do I get the XML data into the Crosshairs collection. I've currently got this in my toolTip constructor class:

    Crosshairs c = new Crosshairs();
    c.SetProperty("a",new {width="3", color="green"});
    c.SetProperty("b", new { width = "3", color = "blue" });
    crosshairs.Add(c);
    

I'm assuming where I've got the new width color is where I would want it to bring in the details from the XML file mentioned above.

  1. I've added in the Converter class but the output I'm now getting is something like:

    tooltip: { borderColor: "#F00" crosshairs: { List: [ { Value: { width: "3" color: "green" } Text: { width: "3" color: "blue" } } ] } enabled: true

    }

I did change the example converter to have the following rows:

foreach (Crosshairs item in listType) {
    //Add each entry to the dictionary.
    Dictionary<string, object> listDict = new Dictionary<string, object>();
    listDict.Add("Value", item.GetProperty("a"));
    listDict.Add("Text", item.GetProperty("b"));
    itemsList.Add(listDict);
}
result["List"] = itemsList;

As you can see it' doesn't look very generic as it uses types of "CrosshairsCollection", but I'm sort of guessing that I can change the "CrosshairsCollection" to a "GenericCollection" as it's only a dictionary - so #1 above still applies.

  1. The other problem is that not only the toolTip has this "crosshairs" class, but I do have other classes that are similar to crosshairs - eg style which I would like to have the same system.

If anyone could help with #1 above - importing the data from XML - to generic class rather than a predefined class it would really help.

Again - Many thanks for the help. Alan

2
  • 1
    How does the ToolTip class look like? Can you post the definition of the class? Commented Apr 20, 2011 at 14:33
  • Thanks, Ive added it above. I've remmed out the crosshairs part as I couldn't get it to work. As you can see the tooltip class has a HCCSS style class in it, If I can get the crosshairs bit working then this would be useful in other classes... like the CSS style class. Commented Apr 20, 2011 at 14:53

1 Answer 1

2

Define a simple Crosshairs type that is a wrapper for a string, object dictionary:

class CrosshairsCollection : List<Crosshairs>
{

}

class Crosshairs
{
    private Dictionary<string, object> dict = new Dictionary<string,object>();

    public IEnumerable<KeyValuePair<string, object>> GetAllProperties()
    {
        foreach (string key in dict.Keys)
        {
            yield return new KeyValuePair<string, object>(key, dict[key]);
        }
    }

    public object GetProperty(string s)
    {
        object value;

        bool exists = dict.TryGetValue(s, out value);
        if (!exists)
        {
            value = null;
        }

        return value;
    }

    public void SetProperty(string s, object o)
    {
        if (!dict.ContainsKey(s))
        {
            dict.Add(s, o);
        }
        else
        {
            dict[s] = o;
        }
    }
}

Then implement a JavaScriptConverter for CrosshairsCollection, similar to this: http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptconverter.aspx

Replace your List with CrosshairsCollection and register the JavaScriptConverter with your JavaScriptSerializer instance.

[Edit: answers to follow up questions]

I'm assuming that you have two follow-up questions, both numbered 1, and that the second one is "how do I get the JSON output to be more like my original example?" :)

The way I interpreted your original XML was that a tooltip has multiple crosshairs, and not a single crosshairs with multiple, overlapping property definitions. The representation in the XML and your name usage in the code aren't in accord though: you call the entire thing "crosshairs." Bear that in mind as you're reading my original and edited response.

So to get an object that mimics the original XML, I would have expected you to provide the properties like so:

CrosshairsCollection crosshairsList = new CrosshairsCollection();

Crosshairs c1 = new Crosshairs();
c1.SetProperty("width", 3);
c1.SetProperty("color", "green");
c1.SetProperty("padding", "5px");
crosshairsList.Add(c1);

Crosshairs c2 = new Crosshairs();
c2.SetProperty("width", 3);
c2.SetProperty("color", "blue");
crosshairsList.Add(c2);

Take that one step further, turn each Crosshairs initialization into a factory method, and plug it into your XML representation, like you're doing in the HCToolTip constructor.

Then, you can add each name value pair into the JSON output as they are:

foreach (Crosshairs crosshairs in crosshairsList) {
    Dictionary<string, object> crosshairProps = new Dictionary<string, object>();

    foreach (KeyValuePair<string, object> prop in crosshairs.GetAllProperties()) {
        crosshairProps.Add(prop.Key, prop.Value);
    }

    itemsList.Add(crosshairProps);
}

result["crosshairs"] = itemsList;

You might need to implement a JavaScriptConverter one level higher up, on ToolTip, in order to get an anonymous list as the property value for ToolTip.crosshairs.

I hope what this is showing though is that really all you're looking for is a key/value collection. I named the classes CrosshairsCollection and Crosshairs to try to draw the distinction between a list of <crosshairs> tags and the subtree of a <crosshairs> tag. But you could name them MultiPropertyItemCollection and MultiPropertyItem, or whatever, because there's nothing type specific in the implementation.

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

3 Comments

Thanks for the reply. I'll try this tomorrow when I get back to the office.
Not sure how I can do a full reply to this - new to stackoverflow.. Will edit my above question instead.
mcw0933 - Many thanks for expanding your explanation, much appreciated. I've been playing around with what you have and the converter, and finally got something working how it needs to be. though I do need to do more tests on it for other situations. Again thanks for the help!.

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.