Q-bertsuit
Q-bertsuit

Reputation: 3437

Parsing an XML file and creating a list of its contents

I'm trying to read an XML file and parse its content, but I'm having trouble extracting parameters from the file.

The XML file I'm trying to parse looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <register_map>
        <Register ID="1" Index="0x100000" DataType="0x0007" ObjectType="0x07" Name="Device Type"/>
        <Register ID="2" Index="0x100100" DataType="0x0005" ObjectType="0x07" Name="Error Register"/>
    </register_map>
</root>

My code so far looks like this

namespace Test_XML
{
    class Program
    {
        struct RegisterEntry
        {
            public UInt32 index;
            public UInt16 dataType;
            public UInt16 objectType;
            public string name;
        };

        static void Main(string[] args)
        {

            XDocument doc = XDocument.Load("registers.xml");

            var registers = doc.Descendants("register_map");

            foreach (var register in registers)
            {
                // Fill up a list of RegisterEntrys with contents of XML
            }
            Console.ReadLine();
        }
    }
}

How can I extract the parameters from "registers" and place them in a RegisterEntry object?

Upvotes: 1

Views: 95

Answers (4)

jdweng
jdweng

Reputation: 34429

Use xml Linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
                "<root>" +
                    "<register_map>" +
                        "<Register ID=\"1\" Index=\"0x100000\" DataType=\"0x0007\" ObjectType=\"0x07\" Name=\"Device Type\"/>" +
                        "<Register ID=\"2\" Index=\"0x100100\" DataType=\"0x0005\" ObjectType=\"0x07\" Name=\"Error Register\"/>" +
                    "</register_map>" +
                "</root>";

            XDocument doc = XDocument.Parse(xml);

            var results = doc.Descendants("Register").Select(x => new {
                id = (int)x.Attribute("ID"),
                index = int.Parse(x.Attribute("Index").Value.Substring(2), NumberStyles.HexNumber,  CultureInfo.CurrentCulture),
                dataType = int.Parse(x.Attribute("DataType").Value.Substring(2), NumberStyles.HexNumber, CultureInfo.CurrentCulture),
                objectType = int.Parse(x.Attribute("ObjectType").Value.Substring(2), NumberStyles.HexNumber, CultureInfo.CurrentCulture),
                name = (string)x.Attribute("Name")
            }).ToList();
        }
    }
}

Upvotes: 1

Charles Mager
Charles Mager

Reputation: 26213

Your query will get you all elements with the name register_map - you want all Register elements. Change it to this:

var registers = doc.Descendants("Registers");

Then iterate through them and take the values you need, converting them to the required types.

foreach (var register in registers)
{
    var indexHex = (string)register.Attribute("Index");
    var index = Convert.ToUInt32(indexHex, 16);

    var dataTypeHex = (string)register.Attribute("DataType");
    var dataType = Convert.ToUInt16(dataTypeHex, 16);

    var objectTypeHex = (string)register.Attribute("ObjectType");
    var objectType = Convert.ToUInt16(objectTypeHex, 16);

    var name = (string)register.Attribute("Name");

    var entry = new RegisterEntry
    {
        index = index,
        dataType = dataType,
        objectType = objectType,
        name = name,
    };

    // do something with entry
}

Upvotes: 1

Marco
Marco

Reputation: 23935

You should use .Attributes["name"].Value. I take it you want those values converted to Int as well, so we need an additional Convert.ToInt(string, base);

var RegisteryEntryList = new List<RegistryEntry>();

foreach (var register in registers)
{
    //create a new RegistryEntry
    var obj = new RegistryEntry();
    //convert your string to an int value and save it
    obj.index = Convert.ToInt32(register.Attributes["Index"].Value.Split('x')[1], 8);
    obj.datatype = Convert.ToInt32(register.Attributes["DataType"].Value.Split('x')[1], 8);

    //... your remaining properties
    RegisteryEntryList.Add(obj);
}

Please note: If your Index is binary (base 2) you need to adapt the conversion accordingly. For more information see https://msdn.microsoft.com/en-us/library/1k20k614(v=vs.110).aspx

Upvotes: 1

Andrey Korneyev
Andrey Korneyev

Reputation: 26876

You can use

var registers = doc.XPathSelectElements("/root/register_map/Register");

It will give you collection of Registernodes, so you wil be able to access their attributes and populate your RegisterEntry object something like:

foreach (var register in registers)
{
    var dataType = register.Attribute("DataType").Value;
    //the rest of the code
}

Notice XPathSelectElements is an extension method in System.Xml.XPath namespace. Make sure you've referenced System.Xml.Linq assembly in order to use it.

Upvotes: 3

Related Questions