views:

111

answers:

5

Hello...Can I use an Array of Dictionary objects?

I have an XML which I would like to modify. The Data Structure that I am to use is this -

Dictionary<element, Dictionary<attr, value>>

element - is the Element which I am about to modify attr - the attribute whose value I am going to update value - the value with which I am to update

<Parents>
    <Parent id="ParentA" description="New">
        <Children>
            <Child name="ChildA" />
        </Children>
    </Parent>
</Parents>

I would want to pass the following

Dictionary<string, string> dict_Attributes1=new Dictionary<string, string>();
Dictionary<string, string> dict_Attributes2=new Dictionary<string, string>();
dict_Attributes1.Add("id", "ParentB");
dict_Attributes1.Add("description", "Old");
dict_Attributes2.Add("name", "ChildB");
Dictionary<string, Dictionary<string, string>> dict_Elements = new Dictionary<string, Dictionary<string, string>>();
dict_Elements.Add(".", dict_Attributes1);//To update the Element
dict_Elements.Add("Children/Child", dict_Attributes2);//To update the Children's Attributes

Let us assume that I have already identified that I am to update Parent whose id is ParentA.

Now, here I am creating dict_Attributes1, dict_Attributes2 etc., is there a way I can have them stored in an (dynamic, size unknown at compile time) Array of Dictionary objects?

Alternatively, is there a better way of doing this - 1. Modify the attributes of a Selected XElement and its children's attributes?

EDIT

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <Environments>
        <Environment id="Master" description="MasterSystem">
            <Systems>
                <DefaultSystem systemName="Master" server="http://localhost" />
            </Systems>
        </Environment>
    </Environments>
</Configuration>

Now, when a user changes the id and description, I want to update this XML file with the new values. While changing the id and description (which are obtained from the user), I want to update the systemName as well with the same value of id.

If the new id is "Development" and description is "DevelopmentSystem",

The output XML should be

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
    <Environments>
        <Environment id="Development" description="DeveloperSystem">
            <Systems>
                <DefaultSystem systemName="Development" server="http://localhost" />
            </Systems>
        </Environment>
    </Environments>
</Configuration>
+2  A: 

There are better options than arrays, which will act the way that I think you want:

var dictionaries = new List<Dictionary<string, string>>();

This is dynamically resizeable, without having to re-copy the contents to a new array. Similar to how you can add new entries to a Dictionary, you can add new items to a list:

var dict = new Dictionary<string, string> { { "Key1", "Value1" }, };
dictionaries.Add(dict);

As for the specific question you asked:

Now, here I am creating dict_Attributes1, dict_Attributes2 etc., is there a way I can have them stored in an (dynamic, size unknown at compile time) Array of Dictionary objects?

Yes, you can create an array of dictionary objects. This is not the same as the dictionary of dictionaries you specified at the top of your code, and isn't easily resizable (though the size can be specified during runtime, and you could "resize" it by making a new array, and copying the contents of the old array).

An array of Dictionaries looks like this:

var dictionaries = new Dictionary<string, string>[0];

If you want to specify the size at run time, just replace [0] with a variable.

Merlyn Morgan-Graham
Merlyn: Thanks. But how? I did a Google (followed by a Bing) search, but to no avail. A code sample, a link to a code sample...anything would do.
Kanini
+1  A: 

You could try using an ArrayList<Dictionary<string,string>>

ArrayList behaves like an array but can be added to dynamically.

Alternately, look at the classes available in System.Xml.Linq

Andrew Cooper
+3  A: 

While what you want to do is allowable, I would personally use LINQ to XML.

There is a slight learning curve, but if you are at least familiar with LINQ and with XML, it will make sense after playing with it a little. It will likely be more efficient than the structures that you are suggesting, and certainly will be easier to adapt and maintain (by you, or especially by somebody else), as they are a standardized technology.

Wonko the Sane
+5  A: 

Yes, it is possible. I'm not sure which of these you need, but they both use a List<T>:

var list = new List<Dictionary<string, string>>();

Or:

var list = new List<Dictionary<string, Dictionary<string, string>>>();
Justin Niessner
A: 

If the goal of this is to edit XML files, you're using the wrong tool for the job. I would strongly suggest using Linq to XML. Here's a pretty simple example of how to modify an XML file using Linq.

using System.Xml.Linq;
//starting with the XML you provided:
/*
<Parents>
    <Parent id="ParentA" description="New">
        <Children>
            <Child name="ChildA" />
        </Children>
    </Parent>
</Parents>
*/

XDocument xdoc = XDocument.Load(@"\path\to\xml\file");

// get the first <child> element (the long way)
XElement xeParents = xdoc.Descendants("Parents").FirstOrDefault();
XElement xeParent = xeParents.Descendants("Parent").FirstOrDefault();
XElement xeChildren = xeParent.Descendants("Children").FirstOrDefault();
XElement xeChild = xeChildren.Descendants("Child").FirstOrDefault();

//Change the value of an attribute
xeParent.SetAttributeValue("id", "ParentB");

//let's add another child for fun
XElement xeChild2 = new XElement("Child");
xeChild2.SetAttributeValue("name", "ChildB");
xeChildren.Add(xeChild2);

xdoc.Save(@"\path\to\save\file");



//a shorter way to get the first <Child> would be:
xeChild = xdoc.Descendants("Child").FirstOrDefault();

//now the XML would look like this: 
/*      
<Parents>
    <Parent id="ParentB" description="New">
        <Children>
            <Child name="ChildA" />
            <Child name="ChildB" />
        </Children>
    </Parent>
</Parents>
*/
jb
jb: Thanks! But what if I want this ModifyXML operation in a function to which I pass the Element I want to update, the list of attr/value pairs, the child elements which I want to update (alongwith the list of attr/value pairs) and XML that I input are 3 three different files?
Kanini
then i'd have to give a whole new answer :)
jb
Let me know if this needs further explaining. I'd use this command: xeElement.Descendants("childname").Where(xe => xe.Attribute("attrname") != null).ToList().ForEach(xe => xe.SetAttributeValue("attrname", "attrvalue"));
jb