1

I have the following XML Document loaded in a XDocument

<XXXXXXXXXXXXXXXXXX xmlns:XXXXX="http://XXXXX/XXXXX/XXXXX/" xmlns:mbs="http://www.microsoft.com/xml">
  <ProdOrderRoutingLine xmlns="Prod. Order Routing Line" />
  <Count>2</Count>
  <Records>
    <Record>
      <Field>
        <Name xmlns="Name">Company-Company-Company-Company</Name>
        <Value xmlns="Value">CRONUS Canada, Inc.</Value>
        <FieldCaption xmlns="FieldCaption">Name</FieldCaption>
      </Field>
      <Field>
        <Name xmlns="Name">Operation No.</Name>
        <Value xmlns="Value">020</Value>
        <Caption xmlns="Caption">Operation No.</Caption>
      </Field>
      <Field>
        <Name xmlns="Name">Line No.</Name>
        <Value xmlns="Value">771521</Value>
        <Caption xmlns="Caption" />
      </Field>
     </Record>
    <Record>
      <Field>
        <Name xmlns="Name">Company-Company-Company-Company</Name>
        <Value xmlns="Value">CRONUS Canada, Inc.</Value>
        <FieldCaption xmlns="FieldCaption">Name</FieldCaption>
      </Field>
      <Field>
        <Name xmlns="Name">Operation No.</Name>
        <Value xmlns="Value">020</Value>
        <Caption xmlns="Caption">Operation No.</Caption>
      </Field>
      <Field>
        <Name xmlns="Name">Line No.</Name>
        <Value xmlns="Value">798122</Value>
        <Caption xmlns="Caption" />
      </Field>
    </Record>
  </Records>
</XXXXXXXXXXXXXXXXXX>

I am trying to read it using LINQ and populate this class for each record

public class Record
{
    public IEnumerable<Field> Fields { get; set; }

    public Record()
    {
        Fields = new List<Field>();
    }
}
public class Field
{
    public string Name { get; set; }
    public string Value { get; set; }
    public string Caption { get; set; }
}

Any proper way of feeding the XML inside my collection is welcome.

I tried messing around with :

var doc = XDocument.Load(@"c:\test\output.xml");

var query = from table in doc.Element("XXXXXXXXXXXXXXXXXX").Element("Records").Elements("Record")
    select new 
{
    name = table.Elements("Field").Attributes("Name"),
    value = table.Elements("Field").Attributes("Value"),
    caption = table.Elements("Field").Attributes("FieldCaption")
};

I get nothing close to what I am looking for.

Seymour
  • 7,043
  • 12
  • 44
  • 51
SerenityNow
  • 1,055
  • 1
  • 15
  • 32

3 Answers3

2

I think you are on the right track but have an issue with your LINQ query.

I don't have time to fully test the following example, but the following looks a bit closer:

        var result = from c in doc.Descendants("Records")
                        select new Record()
                        {
                            Fields = from f in c.Descendants("Field")
                                        select new Field() 
                                        {
                                            Name = f.Element("Name").Value,
                                            Value = f.Element("Value").Value,
                                            Caption = f.Element("FieldCaption").Value
                                        }
                        };

Note: The following links seem to have valuable information:
Parse xml using LINQ to XML to class objects
How to get elements by name in XML using LINQ

Good luck.

Community
  • 1
  • 1
Seymour
  • 7,043
  • 12
  • 44
  • 51
2

I'm not going to the full gory details here but that is a very badly designed XML document. You or the designer of the document needs to read up one the XML standard, in particular, namespaces.

There are namespaces involved in the document. The elements under the Field elements are all namespaced (incorrectly I might add). The Name element is in the namespace: "Name". Value is in the namespace: "Value". And the Caption element is either in the namespace "Caption" or "FieldCaption". You will have to write your query in terms of those namespaces.

This method could help in reading those field elements:

Field ReadField(XElement fieldElement)
{
    XNamespace nsName = "Name";
    XNamespace nsValue = "Value";
    XNamespace nsFieldCaption = "FieldCaption";
    XNamespace nsCaption = "Caption";
    return new Field
    {
        Name = (string)fieldElement.Element(nsName + "Name"),
        Value = (string)fieldElement.Element(nsValue + "Value"),
        // Try the Caption namespace, otherwise try FieldCaption
        Caption = (string)fieldElement.Element(nsCaption + "Caption") ?? (string)fieldElement.Element(nsFieldCaption + "FieldCaption"),
    };
}

Then your query simply becomes this:

var query =
    from record in doc.XPathSelectElements("/XXXXXXXXXXXXXXXXXX/Records/Record")
    select new Record
    {
        Fields = record.Elements("Field")
            .Select(f => ReadField(f))
            .ToList(),
    };
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • I didnt create that XML document but I might be able to get them to change it... can you give me an example of what it should look like. – SerenityNow Dec 06 '13 at 18:11
  • The main problem as far as I can see is the namespaces tacked on to the elements within the `Field` element (`xmlns="..."`). Those are completely unnecessary. Those should be removed. If they were removed, then we could just remove all the `XNamespace` uses in the `ReadField()` method. – Jeff Mercado Dec 06 '13 at 18:24
0

Ok Using the information given by the people above, i ended up

  1. Fixing the XML to normalize the Caption and FieldCaption tags
  2. Removed the XMLNS that were not needed

So now my code is this..

public class Record
{
    public List<Field> Fields { get; set; }
    public Record()
    {
        Fields = new List<Field>();
    }
}

public class Field
{
    public string Name { get; set; }
    public string Value { get; set; }
    public string Caption { get; set; }

    public Field(){}
}

Field ReadField(XElement fieldElement)
{
    return new Field{
        Name = (string)fieldElement.Element("Name"),
        Value = (string)fieldElement.Element("Value"),
        Caption = (string)fieldElement.Element("Caption")
    };
}
void Main()
{

    var lstRecords = new List<Record>();    

    XDocument doc = XDocument.Load(@"c:\fred\output.xml");

var query = from record in doc.XPathSelectElements("/XXXXXXXXXXXXXXXXXX/Records/Record")
select new Record
    {
        Fields = record.Elements("Field").Select (f => ReadField(f)).ToList(),
    };

query.Dump();

}

And It works flawlessly

SerenityNow
  • 1,055
  • 1
  • 15
  • 32