Andrew Truckle
Andrew Truckle

Reputation: 19087

XML serialization and why am I ending up with an ended element?

What am I doing wrong here?

Test XML:

<?xml version="1.0" encoding="utf-8"?>
<CutToolsDatabase xmlns="https//www.trucklesoft.co.uk/cuttools">
  <MaterialGroup>
    <Name>White Back Folding Boxboard - GC1</Name>
    <Material>
      <Name>296Um</Name>
      <Text>
        <Value>Carte Lumina 640x900 200 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>345Um</Name>
      <Text>
        <Value>Carte Lumina 450x640 230 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>368Um</Name>
      <Text>
        <Value>Opus Card 720x1020 260 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>375Um</Name>
      <Text>
        <Value>Carte Lumina 720x1020 250 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>398Um</Name>
      <Text>
        <Value>Opus Card 720x1020 280 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>405Um</Name>
      <Text>
        <Value>Carte Lumina 450x640 270 Gsm</Value>
        <Value>Incada Silk 450x640 260 Gsm </Value>
      </Text>
    </Material>
    <Material>
      <Name>445Um</Name>
      <Text>
        <Value>Incada Silk 450x640 280 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>450Um</Name>
      <Text>
        <Value>Carte Lumina 450x640 300 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>485Um</Name>
      <Text>
        <Value>Incada Silk 450x640 300 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>495Um</Name>
      <Text>
        <Value>Carte Lumina 450x640 330 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>540Um</Name>
      <Text>
        <Value>Incada Silk 520x720 325 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>570Um</Name>
      <Text>
        <Value>Carte Lumina 450x640 380 Gsm</Value>
      </Text>
    </Material>
    <Material>
      <Name>590Um</Name>
      <Text>
        <Value>Incada Silk 450x640 350 Gsm</Value>
      </Text>
    </Material>
  </MaterialGroup>
</CutToolsDatabase>

The class that I have created for this XML:

using System.Collections.Generic;
using System.Xml.Serialization;

namespace CutTools.MaterialsDatabase
{
    [XmlRoot(ElementName = "CutToolsDatabase", Namespace = "https://www.trucklesoft.co.uk/cuttools")]
    public class CutToolsDatabase
    {
        [XmlArray]
        [XmlArrayItem(ElementName = "MaterialGroup")]
        public List<CutToolsDatabaseMaterialGroup> MaterialGroup;

        public CutToolsDatabase()
        {
            MaterialGroup = new List<CutToolsDatabaseMaterialGroup>();
        }
    }

    public class CutToolsDatabaseMaterialGroup
    {
        [XmlElement]
        public string Name;

        [XmlArray]
        [XmlArrayItem(ElementName = "Material")]
        public List<CutToolsDatabaseMaterial> Material;

        public CutToolsDatabaseMaterialGroup()
        {
            Name = "";
            Material = new List<CutToolsDatabaseMaterial>();
        }
    }

    public class CutToolsDatabaseMaterial
    {
        [XmlElement]
        public string Name;

        [XmlArray]
        [XmlArrayItem(ElementName = "Value")]  
        public List<string> Text;

        public CutToolsDatabaseMaterial()
        {
            Name = "";
            Text = new List<string>();
        }
    }
}

The code that i use to load the XML file:

private bool ReadMaterialsData(ref CutToolsDatabase docMaterialsDB)
{
    bool bRead = false;
    try
    {
        System.Reflection.Module mod = GetType().Module;
        string strPath = Path.GetDirectoryName(mod.FullyQualifiedName);
        XmlSerializer x = new XmlSerializer(docMaterialsDB.GetType());
        Bricscad.ApplicationServices.Application.ShowAlertDialog(Path.Combine(strPath, "Materials.xml"));
        using (StreamReader reader = new StreamReader(Path.Combine(strPath, "Materials.xml")))
        {
            docMaterialsDB = (CutToolsDatabase)x.Deserialize(reader);

            bRead = true;
        }
    }
    catch (System.Exception ex)
    {

    }

    return bRead;
}

So why I try the above like this:

CutToolsDatabase _docMaterialsDB = new CutToolsDatabase();
ReadMaterialsData(ref _docMaterialsDB);
_AcAp.Application.ShowAlertDialog(_docMaterialsDB.MaterialGroup.Count.ToString());

The result displayed is 0. What is wrong? I can read the xml file manually and use select paths so what have I done wrong?

I wrote a routine to add some elements and save it to XML. Why is it looking like this?

<?xml version="1.0" encoding="utf-8"?>
<CutToolsDatabase xmlns="https://www.trucklesoft.co.uk/cuttools">
  <MaterialGroup>
    <MaterialGroup>
      <Name>Andrew Group</Name>
      <Material>
        <Material>
          <Name>Andrew Material</Name>
          <Text>
            <Value>Andrew Value</Value>
          </Text>
        </Material>
      </Material>
    </MaterialGroup>
  </MaterialGroup>
</CutToolsDatabase>

Upvotes: 2

Views: 52

Answers (2)

jdweng
jdweng

Reputation: 34421

The following code is tested. XML Serialization an XmlArray is two XML tags (parent and child). You only have one tag so you need to use XmlElement instead.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);

            XmlSerializer serializer = new XmlSerializer(typeof(CutToolsDatabase));

            CutToolsDatabase db = (CutToolsDatabase)serializer.Deserialize(reader);

        }
    }
    [XmlRoot(ElementName = "CutToolsDatabase", Namespace = "https//www.trucklesoft.co.uk/cuttools")]
    public class CutToolsDatabase
    {
        public CutToolsDatabaseMaterialGroup MaterialGroup;
    }

    public class CutToolsDatabaseMaterialGroup
    {
        [XmlElement]
        public string Name;

        [XmlElement(ElementName = "Material")]
        public List<CutToolsDatabaseMaterial> Material;

        public CutToolsDatabaseMaterialGroup()
        {
            Name = "";
            Material = new List<CutToolsDatabaseMaterial>();
        }
    }

    public class CutToolsDatabaseMaterial
    {

        public string Name;

        [XmlElement(ElementName = "Text")]
        public List<Text> Text;

        public CutToolsDatabaseMaterial()
        {
            Name = "";
        }
    }
    public class Text
    {
        public string Value { get; set; }
    }
}

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062502

[XmlArray]+[XmlArrayItem] represent doubly nested scenarios - like:

<Foos>
   <Foo/>
   <Foo/>
   <Foo/>
</Foos>

However, in your cases, they are all singly nested, so: you should use [XmlElement] instead:

[XmlRoot(ElementName = "CutToolsDatabase", Namespace = "https//www.trucklesoft.co.uk/cuttools")]
public class CutToolsDatabase
{
    [XmlElement(ElementName = "MaterialGroup")]
    public List<CutToolsDatabaseMaterialGroup> MaterialGroups { get; }

    public CutToolsDatabase()
    {
        MaterialGroups = new List<CutToolsDatabaseMaterialGroup>();
    }
}

public class CutToolsDatabaseMaterialGroup
{
    [XmlElement]
    public string Name { get; set; }

    [XmlElement(ElementName = "Material")]
    public List<CutToolsDatabaseMaterial> Material;

    public CutToolsDatabaseMaterialGroup()
    {
        Name = "";
        Material = new List<CutToolsDatabaseMaterial>();
    }
}

public class CutToolsDatabaseMaterial
{
    [XmlElement]
    public string Name { get; set; }

    [XmlElement]
    public Text Text { get; set; }

    public CutToolsDatabaseMaterial()
    {
        Name = "";
        Text = new Text();
    }
}

public class Text
{
    [XmlElement]
    public string Value { get; set; }
}

Upvotes: 2

Related Questions