3

I'm a bit out of my element. I've used xsd.exe to create an xsd schema from an xml file, and then to create a C# class from that xsd. That all seems to work fine.

At the moment I'm just trying to get the XML deserialized. The file I'm deserializing if the very same file I used to build the class originally. Here's my code:

String xsdPath=@"C:\Users\tol56881\Documents\dnd4e.xsd";
String xmlPath=@"C:\Users\tol56881\Documents\dnd4e.xml";
String xsdNamespace="";

//Validation stuff
XmlParserContext context = new XmlParserContext(null, null, "", XmlSpace.None);
XmlValidatingReader vr = new XmlValidatingReader(xmlPath, XmlNodeType.Element, context);
vr.ValidationType = ValidationType.Schema;
vr.Schemas.Add(xsdNamespace, xsdPath);
while (vr.Read()) ;

//Actually reading the file
TextReader tr = new StreamReader(xmlPath);
D20Character character = (D20Character)(new XmlSerializer(typeof(D20Character))).Deserialize(tr);

It compile fine, but when I try to run it I get the an error that's repeated for four different objects. I've given an example below, changing the names of the objects.

Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'Namespace.ObjectName[]' to 'Namespace.ObjectName'
error CS0029: Cannot implicitly convert type 'Namespace.ObjectName' to 'Namespace.ObjectName[]'

So it seems like the program is trying to go from array to object and back to array, but I'm not really sure. The auto-generated class code is a huge mess that's difficult to wade through. I'm hoping that maybe there's something simple I'm missing here.

Thanks!

Asmor
  • 5,043
  • 6
  • 32
  • 42
  • Hmm, parsing DDI Character Builder files? I'll take a look later and see if I can offer any thoughts. – Tetsujin no Oni May 01 '09 at 19:08
  • Indeed. They were kind enough in the last update to make the XML files friendlier to third parties, so figured I'd take them up on it. I did manage to fix it. About to add details on the fix, though I'm leaving the problem open since I don't understand why the problem came up in the first place. – Asmor May 01 '09 at 19:18
  • It's an old question but still valid, and here's more information in case anyone else runs into this: http://blog.coderunnr.com/2012/06/net-xmlserializer-unable-to-generate-a-temporary-class/. The post includes a slightly more elegant solution (adding an attribute to the schema) with an example. The problem is actually a bug in .NET's XmlSerializer: http://connect.microsoft.com/VisualStudio/feedback/details/349967/xsd-exe-generates-code-with-the-wrong-type-in-an-xmlarrayitemattribute – spork Jun 05 '12 at 18:56

2 Answers2

10

I managed to fix this. Each of the four objects in question were generated as doubly-indexed arrays, such as:

    private loot[][] lootTallyField;

and

    public loot[][] LootTally
    {
        get
        {
            return this.lootTallyField;
        }
        set
        {
            this.lootTallyField = value;
        }
    }

All I did was remove one set of brackets, and it all seems to be working fine. No problems with deserialization and a quick inspection of the deserialized object makes it look like the data was loaded correctly.

    private loot[] lootTallyField;

and

    public loot[] LootTally
    {
        get
        {
            return this.lootTallyField;
        }
        set
        {
            this.lootTallyField = value;
        }
    }

Still not sure why xsd.exe made these doubly-indexed if they're not supposed to be. I feel like I'm still missing something, hence why this question is still open.

Particularly, if I ever need to re-generate this code, then I'd need to reapply the fix, which kind of defeats the purpose of using a partial class in the first place...

Asmor
  • 5,043
  • 6
  • 32
  • 42
  • Instead of changing the generated class, you can also edit the generated XSD file by removing the maxOccurs="unbounded" attribute for elements that should not be arrays (this is the cause of these 2d-arrays) – Stefan Woehrer Jun 01 '17 at 11:56
7

There is a problem on xsd.exe tool, I will try to explain.

If you have a complexType with a sequence inside that has a child complexType with a sequence and the first one does not have any other elements / attributes, then the generated class will have only 1 generated type, instead of 2 and it will be a double array.

If you make the double array into a single array, you will be able to deserialize your xml just fine. HOWEVER this will produce the following unexpected result. If your xml looks like the below.

<root>
    <loot>
        <tally>value1</tally>
        <tally>value2</tally>
    </loot>
    <loot>
        <tally>value3</tally>
        <tally>value4</tally>
    </loot>
</root>

Then your deserialized object, in the lootTally array would only contain the value3 and value4 items instead of having all 4.

So you have 2 options to fix this correctly:

  1. Alter the xsd file by adding a dummy in the first sequence, and run xsd.exe again, so that when it generates the class it will not create a double array, and then you can delete the dummy attribute from the class.
  2. Alter the generated class, add a new class named loot which will contain an array of tally objects which you already have (and only need to alter the name).

Please note that in option 2 you may have to change some declarations if you have an XmlArrayItemAttribute to XmlElementAttribute.

Hope this helps

A Kalli
  • 81
  • 1
  • 3
  • This is a great answer. Saved me tons of time. I generated a SalesForce Enterprise WSDL and used VS2017 to generate POCOs from that file but I got the doubly indexed arrays as well. – Adrian Jul 04 '17 at 19:51