1
votes

Is there a way to emulate using command line with the xsd.exe what happens when you click the 'Create Schema' option under the XML tab in Visual Studio?

I am trying to automate the process of creating schemas from XML in order to create classes using the XSD.

when I use the xsd file.xml command I get an error: Cannot add a column named 'MyXMLElement': a nested table with the same name already belongs to this DataTable. However, it works fine when I use the Create Schema option in VS2010.

<Person xmlns="http://someNamespace/1.0" xmlns:j="http://www.google.com/2.0" xmlns:nc="http://yahoo.com/3.0">   
    <MainElement>
        <j:FirstElement>
            <nc:SecondElement>
                <nc:Value>something.com</nc:Value>
            </nc:SecondElement>
        </j:FirstElement>
        <nc:FirstElement>
            <ThirdElement>          
                <nc:PersonName>
                    <nc:Value>SomeName</nc:Value>
                </nc:PersonName>
            </ThirdElement>
        </nc:FirstElement>
    </MainElement>
</Person>
2

2 Answers

2
votes

You can run xsd.exe file.xml and it should generate file.xsd, a schema for the instance document.

I tried your edited sample and ran into the same error. I thought that approach worked but it seems I was wrong. As an alternative, .NET has the System.Xml.Schema.XmlSchemaInference class that I have tested not to throw an error:

        XmlSchemaInference xs = new XmlSchemaInference();
        XmlSchemaSet schemaSet;

        using (XmlReader xr = XmlReader.Create("file.xml"))
        {
            schemaSet = xs.InferSchema(xr);
        }

        foreach (XmlSchema schema in schemaSet.Schemas())
        {
            Console.WriteLine(schema.TargetNamespace);
            schema.Write(Console.Out);
            Console.WriteLine();
        }

Of course instead of writing the schemas for testing to the console you could save them to files. There is one problem, in my test with your files three schemas are created in the schema set, one for each target namespace, and the main one does e.g. <xs:import namespace="http://www.google.com/2.0" /> to import the other ones but as there are no files, the schema.Write does not output any location.

That is all I can currently suggest, I realize it is not a complete solution but perhaps it helps you solve the problem.

0
votes

This is what I ended up doing to create an XSD from an .xml file and then convert the XSD into a class or classes and save the class file.

Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Xml
Imports System.Xml.Schema
Imports System.Xml.Serialization
Imports System.CodeDom
Imports System.CodeDom.Compiler

Public Class XMLToClass
    Implements IXMLToClass

    Public Sub New()
    End Sub

    Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IXMLToClass.GetDataUsingDataContract

        Return composite
    End Function



    Public Sub GenerateClassFromXML(ByVal XMLfileName As String, ByVal OutPutFilePath As String, ByVal CodeNameSpace As String)
        Dim xs As New XmlSchemaInference()
        Dim schemaSet As XmlSchemaSet
        Dim schemas As New XmlSchemas()
        Using xr As XmlReader = XmlReader.Create(XMLfileName)
            xs.TypeInference = XmlSchemaInference.InferenceOption.Relaxed
            xs.Occurrence = XmlSchemaInference.InferenceOption.Relaxed
            schemaSet = xs.InferSchema(xr)
        End Using

        For Each Schema As XmlSchema In schemaSet.Schemas
            schemas.Add(Schema)
        Next
        PersistClass(schemas, OutPutFilePath, CodeNameSpace)

    End Sub

    Public Sub PersistClass(ByVal schemas As XmlSchemas, ByVal OutPutFileName As String, ByVal namesp As String)

        ' Get the namespace for the schema.
        Dim ns As CodeNamespace = XsdGenerator.Processor.Process(schemas, namesp)
        ' Create the appropriate generator for the language.
        Dim provider As CodeDomProvider
        provider = New Microsoft.VisualBasic.VBCodeProvider()
        ' Write the code to the output file.
        Using sw As New StreamWriter(OutPutFileName, False)
            provider.GenerateCodeFromNamespace(ns, sw, New CodeGeneratorOptions())
        End Using

    End Sub
End Class

Namespace XsdGenerator
    Public NotInheritable Class Processor
        Public Shared Function Process(ByVal schemas As XmlSchemas, targetNamespace As String) As CodeNamespace

            ' Create the importer for these schemas.
            Dim importer As New XmlSchemaImporter(schemas)
            ' System.CodeDom namespace for the XmlCodeExporter to put classes in.
            Dim ns As New CodeNamespace(targetNamespace)
            Dim exporter As New XmlCodeExporter(ns)
            ' Iterate schema top-level elements and export code for each.
            For Each xsd As XmlSchema In schemas
                For Each element As XmlSchemaElement In xsd.Elements.Values
                    ' Import the mapping first.
                    Dim mapping As XmlTypeMapping = importer.ImportTypeMapping(element.QualifiedName)
                    ' Export the code finally.
                    exporter.ExportTypeMapping(mapping)
                Next
            Next

            Return ns
        End Function
    End Class
End Namespace