levelonehuman
levelonehuman

Reputation: 1505

Reading XML to DataSet with multiple tables in file

I'm working on building an XML editor for a personal project. Using WinForms DataGridView control and DataSet, I was able to set up Read/Edit/Save with little issue, using a separate XML file for each type.

However, as I started to try adding more "advanced" controls, it became cumbersome to work with several different files - requiring if statements depending on which file I was working with. So, I tried combining these files into one larger file, as below:

<?xml version="1.0" encoding="utf-8" ?>
<Items>
  <Armor>
    <Item>
      <Name>Test Armor</Name>
      <Value>1234567</Value>
      <Rarity>Common</Rarity>
      <Slot>Chest</Slot>
      <Damage>1234567</Damage>
      <Defense>1234567</Defense>
      <Health>1234567</Health>
      <Mana>1234567</Mana>
      <Strength>1234567</Strength>
      <Dexterity>1234567</Dexterity>
      <FlavorText>Something about stuff</FlavorText>
      <ImageSource>C:\Items\img.gif</ImageSource>
    </Item>
  </Armor>
  <Consumables>
    <Item>
      <Name>Test Potion</Name>
      <Value>1234567</Value>
      <Damage>1234567</Damage>
      <Defense>1234567</Defense>
      <Health>0.1234567</Health>
      <Mana>0.1234567</Mana>
      <Strength>1234567</Strength>
      <Dexterity>1234567</Dexterity>
      <FlavorText>Something about stuff</FlavorText>
      <ImageSource>C:\Items\img.gif</ImageSource>
    </Item>
  </Consumables>
  <Junk>
    <Item>
      <Name>Test Junk</Name>
      <Value>1234567</Value>
      <Stackable>Yes</Stackable>
      <FlavorText>Something about stuff</FlavorText>
      <ImageSource>C:\Items\img.gif</ImageSource>
    </Item>
  </Junk>
  <QuestItems>
    <Item>
      <Name>Test Quest Item</Name>
      <Stackable>Yes</Stackable>
      <FlavorText>Something about stuff</FlavorText>
      <ImageSource>C:\Items\img.gif</ImageSource>
    </Item>
  </QuestItems>
  <Weapons>
    <Item>
      <Name>Test Weapon</Name>
      <Value>1234567</Value>
      <Rarity>Common</Rarity>
      <Slot>Primary</Slot>
      <Damage>1234567</Damage>
      <Defense>1234567</Defense>
      <Health>1234567</Health>
      <Mana>1234567</Mana>
      <Strength>1234567</Strength>
      <Dexterity>1234567</Dexterity>
      <FlavorText>Something about stuff</FlavorText>
      <ImageSource>C:\Items\img.gif</ImageSource>
    </Item>    
  </Weapons>
</Items>

And the schema, generated from Visual Studio's Create Schema menu, and minimally modified - such as changing unsignedInt to int:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Items">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Armor">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Name" type="xs:string" />
                    <xs:element name="Value" type="xs:int" />
                    <xs:element name="Rarity" type="xs:string" />
                    <xs:element name="Slot" type="xs:string" />
                    <xs:element name="Damage" type="xs:int" />
                    <xs:element name="Defense" type="xs:int" />
                    <xs:element name="Health" type="xs:int" />
                    <xs:element name="Mana" type="xs:int" />
                    <xs:element name="Strength" type="xs:int" />
                    <xs:element name="Dexterity" type="xs:int" />
                    <xs:element name="FlavorText" type="xs:string" />
                    <xs:element name="ImageSource" type="xs:string" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Consumables">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Name" type="xs:string" />
                    <xs:element name="Value" type="xs:int" />
                    <xs:element name="Damage" type="xs:int" />
                    <xs:element name="Defense" type="xs:int" />
                    <xs:element name="Health" type="xs:decimal" />
                    <xs:element name="Mana" type="xs:decimal" />
                    <xs:element name="Strength" type="xs:int" />
                    <xs:element name="Dexterity" type="xs:int" />
                    <xs:element name="FlavorText" type="xs:string" />
                    <xs:element name="ImageSource" type="xs:string" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Junk">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Name" type="xs:string" />
                    <xs:element name="Value" type="xs:int" />
                    <xs:element name="Stackable" type="xs:string" />
                    <xs:element name="FlavorText" type="xs:string" />
                    <xs:element name="ImageSource" type="xs:string" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="QuestItems">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Name" type="xs:string" />
                    <xs:element name="Stackable" type="xs:string" />
                    <xs:element name="FlavorText" type="xs:string" />
                    <xs:element name="ImageSource" type="xs:string" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Weapons">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Item" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Name" type="xs:string" />
                    <xs:element name="Value" type="xs:int" />
                    <xs:element name="Rarity" type="xs:string" />
                    <xs:element name="Slot" type="xs:string" />
                    <xs:element name="Damage" type="xs:int" />
                    <xs:element name="Defense" type="xs:int" />
                    <xs:element name="Health" type="xs:int" />
                    <xs:element name="Mana" type="xs:int" />
                    <xs:element name="Strength" type="xs:int" />
                    <xs:element name="Dexterity" type="xs:int" />
                    <xs:element name="FlavorText" type="xs:string" />
                    <xs:element name="ImageSource" type="xs:string" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Both of these files are wholly representative of their counterparts - I had separate files for Armor, Consumables, etc.

The expected outcome was to have one file representing the previously separate files, such that:

Items is the root node.
Within Items are the parent nodes - Armor, Consumables, etc.
Within each parent node are the child nodes Item and their properties.

As far as I can tell, the XML structure and schema looks correct, but when I try to read this file into my program, I receive the error: System.FormatException - "Input string was not in a correct format.".

The stack trace shows that System.Number.StringToNumber is throwing this exception. I've dug through the file and the schema a few times and can't seem to find where this is occuring, and the exception detail doesn't provide much further detail.

In my code, I'm reading the data simply using

DataSet data = new DataSet();            

data.ReadXmlSchema(itemSchema);
data.ReadXml(itemData);

This exact method worked without issue when the files/schema were separate, which further leads me to believe I've simply overlooked something in the XML/Schema.

At this point, I'm stuck and not sure what it could be. I would greatly appreciate if anyone can help me solve this issue.

Upvotes: 0

Views: 1676

Answers (1)

Josh Part
Josh Part

Reputation: 2164

The problem is that you repeat the element Item on each item type. When your code reads the schema, it finds the first appearance of the Item element and tries to apply the same schema to every other appearance; so, when it reads the Test Potion it tries to read it as string, int, string, string, int, int, int, int, int, int, string, string and fails when it finds the 0.1234567 Health value.

My suggestion would be to change your schema it to something like this:

<?xml version="1.0" encoding="utf-8" ?>
<Items>
  <Armor>
    <ArmorItem>
    ...Item elements
    </ArmorItem>
  </Armor>
  <Consumables>
    <ConsumableItem>
    ...Item elements
    </ConsumableItem>
  </Consumables>
  <Junk>
    <JunkItem>
    ...Item elements
    </JunkItem>
  </Junk>
  <QuestItems>
    <QuestItem>
    ...Item elements
    </QuestItem>
  </QuestItems>
  <Weapons>
    <WeaponItem>
    ...Item elements
    </WeaponItem>    
  </Weapons>
</Items>

Upvotes: 1

Related Questions