Robert Snyder
Robert Snyder

Reputation: 2409

Deserialize Xml to different type

This question may be that I am not asking the question correctly but the conflicting names and classes make it difficult. I'm wanting to build up a small tool which tracks my code metrics as I refactor some code. The results now output to a file which I am trying to deserialize. Here is a snippit of the metrics. (Sorry that is as small as I could make it)

<CodeMetricsReport Version="11">
<Targets>
    <Target Name="C:\Git\coab\GoldBox.Logging\bin\Debug\GoldBox.Logging.dll">
    <Modules>
        <Module Name="GoldBox.Logging.dll" AssemblyVersion="1.0.5978.28510">
        <Metrics>
            <Metric Name="MaintainabilityIndex" Value="88" />
            <Metric Name="CyclomaticComplexity" Value="30" />
            <Metric Name="ClassCoupling" Value="13" />
            <Metric Name="DepthOfInheritance" Value="1" />
            <Metric Name="LinesOfCode" Value="51" />
        </Metrics>
        <Namespaces>
            <Namespace Name="GoldBox.Logging">
            <Metrics>
                <Metric Name="MaintainabilityIndex" Value="88" />
                <Metric Name="CyclomaticComplexity" Value="30" />
                <Metric Name="ClassCoupling" Value="13" />
                <Metric Name="DepthOfInheritance" Value="1" />
                <Metric Name="LinesOfCode" Value="51" />
            </Metrics>
            <Types>
                <Type Name="Config">
                <Metrics>
                    <Metric Name="MaintainabilityIndex" Value="89" />
                    <Metric Name="CyclomaticComplexity" Value="9" />
                    <Metric Name="ClassCoupling" Value="5" />
                    <Metric Name="DepthOfInheritance" Value="1" />
                    <Metric Name="LinesOfCode" Value="15" />
                </Metrics>
                <Members>
                    <Member Name="BasePath.get() : string" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="8">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="98" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="0" />
                        <Metric Name="LinesOfCode" Value="1" />
                    </Metrics>
                    </Member>
                    <Member Name="BasePath.set(string) : void" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="8">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="95" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="0" />
                        <Metric Name="LinesOfCode" Value="1" />
                    </Metrics>
                    </Member>
                    <Member Name="LogPath.get() : string" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="9">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="98" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="0" />
                        <Metric Name="LinesOfCode" Value="1" />
                    </Metrics>
                    </Member>
                    <Member Name="LogPath.set(string) : void" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="9">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="95" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="0" />
                        <Metric Name="LinesOfCode" Value="1" />
                    </Metrics>
                    </Member>
                    <Member Name="SavePath.get() : string" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="10">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="98" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="0" />
                        <Metric Name="LinesOfCode" Value="1" />
                    </Metrics>
                    </Member>
                    <Member Name="SavePath.set(string) : void" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="10">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="95" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="0" />
                        <Metric Name="LinesOfCode" Value="1" />
                    </Metrics>
                    </Member>
                    <Member Name="Setup() : void" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="13">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="67" />
                        <Metric Name="CyclomaticComplexity" Value="1" />
                        <Metric Name="ClassCoupling" Value="3" />
                        <Metric Name="LinesOfCode" Value="7" />
                    </Metrics>
                    </Member>
                    <Member Name="CreateIfNeeded(string) : void" File="C:\Git\coab\GoldBox.Logging\Config.cs" Line="25">
                    <Metrics>
                        <Metric Name="MaintainabilityIndex" Value="84" />
                        <Metric Name="CyclomaticComplexity" Value="2" />
                        <Metric Name="ClassCoupling" Value="1" />
                        <Metric Name="LinesOfCode" Value="2" />
                    </Metrics>
                    </Member>
                </Members>
                </Type>
            </Types>
            </Namespace>
        </Namespaces>
        </Module>
    </Modules>
    </Target>
</Targets>
</CodeMetricsReport>

I was working my way down with

void Main()
{
    var xml = XElement.Load(@"C:\Git\coab\MetricResults\immer@DESKTOP-2KSR2T6 2016-05-15 05_27_14.mrx");
    XmlSerializer serializer = new XmlSerializer(typeof(Target));
    xml.Dump();
    xml.Descendants("Target")
        .Select(e=>(Target)serializer.Deserialize(e.CreateReader()))
        .Dump();
}
public class Target 
{
    [XmlAttribute]
    public string Name {get;set;}
    public List<Module> Modules {get;set;}
}
public class Module
{
    [XmlAttribute]
    public string Name {get;set;}

    [XmlAttribute]
    public string AssemblyVersion {get;set;}

    public List<Metric> Metrics {get;set;}
    public List<Namespace> Namespaces {get;set;}
}
public class Namespace
{
    [XmlAttribute]
    public string Name {get;set;}
    public List<Metric> Metrics {get;set;}
    public List<Type> Types {get;set;}
}

public class Type
{
    [XmlAttribute]
    public string Name {get;set;}
    public List<Metric> Metrics {get;set;}

}
public class Metric
{
    [XmlAttribute]
    public string Name {get;set;}

    [XmlAttribute]
    public string Value {get;set;}
}

When I got to Type I knew that I could depend on LinqPad putting my Type in its own unique namespace and the code would work. However for the code I want to write I don't want it to be Type, I'd rather it be MetricType however when I change the Type to MetricType in the class Namespace I get back zero results. So the question is how can I make Namespace look like this instead?

public class Namespace
{
    [XmlAttribute]
    public string Name {get;set;}
    public List<Metric> Metrics {get;set;}
    public List<MetricType> Types {get;set;}
}
public class MetricType
{
    [XmlAttribute]
    public string Name {get;set;}
    public List<Metric> Metrics {get;set;}
}

Upvotes: 0

Views: 611

Answers (1)

Charles Mager
Charles Mager

Reputation: 26213

The serialiser will infer element and attribute names from the type and property names. If you want different names, you have to add attributes to explicitly define the names you want to use.

The attribute you want here is XmlArrayItem, which specifies the name for the items within the list:

public class Namespace
{
    [XmlAttribute]
    public string Name { get; set; }

    public List<Metric> Metrics { get; set; }

    [XmlArrayItem("Type")]
    public List<MetricType> Types { get; set; }
}

Just to give you more of a flavour, if you wanted to be explicit about all names in this class, you'd need these attributes:

[XmlRoot("Namespace")
public class Namespace
{
    [XmlAttribute("Name")]
    public string Name { get; set; }

    [XmlArray("Metrics")]
    [XmlArrayItem("Metric")]
    public List<Metric> Metrics { get; set; }

    [XmlArray("Types")]
    [XmlArrayItem("Type")]
    public List<MetricType> Types { get; set; }
}

See this fiddle for a working demo.

Upvotes: 1

Related Questions