Natzely
Natzely

Reputation: 706

Dealing with root nodes inside root nodes in XML with C#

Sorry for the horrible title, I wasn't sure what the proper phrasing is.

I've been using this code to parse some XML:

[Serializable()]
public class Report
{
    [XmlElement("AttachedFiles")]
    public AttachedFiles attachedFiles;

    public Report()
    {
        attachedFiles = null;
    }
}

[Serializable()]
[XmlRoot("nodes")]
public class ReportList
{
    [XmlElement("node", typeof(Report))]
    public Report[] reportList;
}

[Serializable()]
[XmlRoot("AttachedFiles")]
public class AttachedFiles
{
    [XmlElement("AttachedFile")]
    public List<string> attachedFiles;
}

The XML looks something like this:

<nodes>
    <node>
        <AttachedFiles>
            <AttachedFile>File1</AttachedFile>
            <AttachedFile>File2</AttachedFile>
        </AttachedFiles>
    </node>
</nodes>

The problem I'm having is that this ends up with me having to call Report.attachedFiles.attachedFiles to get the List. Is there a way for me to only call Report.attachedFiles and get the List? I know this is a really minor problem, but it's bothering quite a bit.

EDIT

This is what the code looks like after help from @xDaevax.

[Serializable()]
public class Report
{
    [XmlArray(ElementName = "AttachedFiles"), XmlArrayItem(ElementName = "AttachedFile")]
    public List<string> AttachedFiles;

    public Report()
    {
        attachedFiles = null;
    }
}

[Serializable()]
[XmlRoot("nodes")]
public class ReportList
{
    [XmlElement("node", typeof(Report))]
    public Report[] reportList;
}

Thanks for the help!

Upvotes: 0

Views: 61

Answers (1)

xDaevax
xDaevax

Reputation: 2022

Here is what I came up with (though I did not have your JiraReport class handy).

[Serializable()]
public class Report {

    [XmlIgnore()]
    private AttachedFiles _attachedFiles;
    public Report() {
            attachedFiles = null;
    } // end constructor

    [XmlArray(ElementName = "AttachedFiles"), XmlArrayItem(ElementName = "AttachedFile")]
    public AttachedFiles Files {
            get { return _attachedFiles; }
            set { _attachedFiles = value; }
    } // end property Files

} // end class Report

[Serializable()]
[XmlRoot("ReportList")]
public class ReportList {

    [XmlIgnore()]
    private Report[] _reports;

    public ReportList() {
        _reports = null;
    } // end constructor

    [XmlArray(ElementName = "nodes"), XmlArrayItem(ElementName = "node")]
    public Report[] Reports {
            get { return _reports; }
            set { _reports = value; }
    } // end property Reports

} // end class ReportList

[Serializable()]
public class AttachedFiles : List<string> {

} // end class AttachedFiles

Using the XmlArray and ArrayItem on a collection property simplifies the attribute usage and makes the code easier to read. Also, because the AttachedFiles class inherits from a list of string, it removes a level of depth from your object graph so the call isn't redundant anymore. You could also add a function on the ReportList class that loops and returns all attached files for all reports for you (functions will not be serialized by the XmlSerializer).

Edit: Here is some MSDN documentation that explains the feature usage:

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlarrayitemattribute(v=vs.100).aspx Also, see this BlackWasp article that has a nice walkthrough of XML serialization involving arrays. http://www.blackwasp.co.uk/xmlarrays.aspx

Upvotes: 1

Related Questions