1

I am new to XML. I need to parse this XML and read the values from the -Field- element and -name- attribute.

I need values from accountID, deviceID, odometerKM

Here is the XML:

<GTSResponse command="dbget" result="success">
    <Record table="EventDataView" partial="true">
        <Field name="accountID" primaryKey="true" alternateKeys="adtkey,driverkey">
            <![CDATA[salesdemo]]>
        </Field>
        <Field name="deviceID" primaryKey="true" alternateKeys="adtkey">
            <![CDATA[bubba_polaris]]>
        </Field>
        <Field name="timestamp" primaryKey="true" alternateKeys="adtkey,driverkey">1605919705</Field>
        <Field name="statusCode" primaryKey="true">0xF010</Field>
        <Field name="latitude">0.0</Field>
        <Field name="longitude">0.0</Field>
        <Field name="odometerKM">0.2566422</Field>
        <Field name="odometerOffsetKM">0.0</Field>
    </Record>
    <Record table="EventDataView" partial="true">
        <Field name="accountID" primaryKey="true" alternateKeys="adtkey,driverkey">
            <![CDATA[salesdemo]]>
        </Field>
        <Field name="deviceID" primaryKey="true" alternateKeys="adtkey">
            <![CDATA[bubba_polaris]]>
        </Field>
        <Field name="timestamp" primaryKey="true" alternateKeys="adtkey,driverkey">1605919705</Field>
        <Field name="statusCode" primaryKey="true">0xF010</Field>
        <Field name="latitude">0.0</Field>
        <Field name="longitude">0.0</Field>
        <Field name="odometerKM">0.23445323</Field>
        <Field name="odometerOffsetKM">0.0</Field>
    </Record>
</GTSResponse>

Here is the code I have tried:

XDocument doc = XDocument.Parse(receivedResponse);

Dictionary<string, string> dataDictionary = new Dictionary<string, string>();

foreach (XElement element in doc.Descendants().Where(p => p.HasElements == false))
{
    int keyInt = 0;
    string keyName = element.Name.LocalName;

    while (dataDictionary.ContainsKey(keyName))
    {
        keyName = element.Name.Namespace.ToString();

        keyName = element.Name.LocalName + "_" + keyInt++;
    }

    dataDictionary.Add(keyName, element.Value);
}

foreach (var x in dataDictionary)
{
    Console.WriteLine("keyName: " + x.Key + " value: " + x.Value);
}

When I run this, it loops through all of the -Field- elements but it does not use the -name-. I need to see the -name- so I know what value I have. I will be updating my database and need to loop through and update fields accordingly by name.

4
  • You need to replace elements to descendents From : .Elements("Field") To : .Descendants("Field") Commented Dec 17, 2020 at 10:13
  • Thanks jdweng - I will try that. Commented Dec 17, 2020 at 16:22
  • What are you trying to do in the while loop? If you want to change value dataDictionary[keyName] = "new value"; Commented Dec 17, 2020 at 18:57
  • I am looping through all elements in the XML file. The XML that I posted was just for one Record. But there are multiple Record elements in the actual data... I dont understand what you have commented to change..... Commented Dec 17, 2020 at 21:54

2 Answers 2

1

There's a Record element that you didn't navigate through.

Try this:

var values =
    doc
        .Root
        .Elements("Record")
        .SelectMany((x, n) => x.Elements("Field").Select(y => new { field = y, index = n }))
        .ToDictionary(
            x => $"{(string)x.field.Attribute("name")}_{x.index}",
            x => (string)x.field);

I get this from your sample data:

values


I think you're better off with this:

Dictionary<int, Dictionary<string, string>> values =
    doc
        .Root
        .Elements("Record")
        .Select((x, n) => (x, n))
        .ToDictionary(
            y => y.n,
            y => y.x
                .Elements("Field")
                .ToDictionary(
                    z => (string)z.Attribute("name"),
                    z => (string)z));

Then you get:

values 2

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

6 Comments

Hi Enigmativity - thanks for helping - here is the error now: System.ArgumentException: 'An item with the same key has already been added.'
@Tdigges - That would be because there are multiple Record elements. It sounds like you need a Dictionary<string, Dictionary<string, string>>. Would that be right?
yes, I have found that to be true as well. I found code to loop through the Dictionary <string, string> but it does not use the -name- as the field. If you have any examples that would be appreciated.
Enigmativity - I updated my CODE above to include the Dictionary<string, string>. If you can assist in showing how to reference the dictionary by -name- I would appreciate.
how do you get that Dictionary View with the Key and Values to display?
|
0

Try following :

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string receivedResponse = File.ReadAllText(FILENAME);
            
            XDocument doc = XDocument.Parse(receivedResponse);

            Dictionary<string, Dictionary<string, List<Field>>> dataDictionary = doc.Descendants("Record")
                .GroupBy(x => (string)x.Attribute("table"), y => y)
                .ToDictionary(x => x.Key, y => y.Elements("Field")
                    .GroupBy(a => (string)a.Attribute("name"), b => new Field(b))
                    .ToDictionary(a => a.Key, b => b.ToList()));
        }
    }
    public class Field
    {
        public string name { get; set; }
        public Boolean? primaryKey { get; set; }
        public string alternateKeys { get; set; }
        public string text { get; set; }

        public Field(XElement field)
        {
            name = (string)field.Attribute("Field");
            primaryKey = (field.Attribute("primaryKey") == null) ? null : (Boolean?)field.Attribute("primaryKey");
            alternateKeys = (field.Attribute("alternateKeys") == null) ? null : (string)field.Attribute("alternateKeys");
            text = (string)field;
        }
    }
 
}

2 Comments

awesome jdweng! That helped me out a lot....... I had make a couple changes to get the value to populate..........
public Field(XElement field) { name = (string)field.Attribute("name"); primaryKey = (field.Attribute("primaryKey") == null) ? null : (Boolean?)field.Attribute("primaryKey"); alternateKeys = (field.Attribute("alternateKeys") == null) ? null : (string)field.Attribute("alternateKeys"); text = field.Value; }

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.