Click here to Skip to main content
15,894,405 members
Articles / Programming Languages / XML

Parsing and Interpreting XSD Using LINQ

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
6 May 2012CPOL2 min read 42.3K   1K   13  
How to use a Linq2Xsd generated object to directly manipulate XmlSchema
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.w3.org.Item2001.XMLSchema;
using System.Xml;

namespace Coding.Bruce.Language.Converter.Ska
{
    public class Ska
    {
        static IndentHelper ind = new IndentHelper();

        public static string FromSchema(schema scm)
        {
            return JoinLines("//",
                "// Ska(c) 2011, Bruce Meacham - An intuitive Xml Schema language",
                string.Format("// DO NOT EDIT - This is file was generated on {0} by ska.exe", DateTime.Now), "//", ind.nl,

                // Simple Types
                JoinLines(scm.simpleType.Select(simp =>
                        WriteSimpleType(simp.Content)).ToArray()),

                // Complex Types
                JoinLines(scm.complexType.Select(comp =>
                    string.Concat("Type ", comp.Content.name,
                        WriteComplexType(comp.Content), ind.nl)).ToArray()),

                // root Element + ref Elements
                WriteElements(true, scm.element.Select(e => (elementType)e.Content))
            );
        }


        private static string WriteSimpleType(simpleTypeType simp)
        {
            return string.Concat("Type ", simp.name, WriteSimple(simp), ind.nl);
        }

        internal static string WriteSimple(simpleTypeType simp)
        {
            var rest = simp.restriction;
            var baseTyp = rest.@base;

            var typ = (null == baseTyp || baseTyp.ToString().EndsWith(":string")) ? string.Empty :
                    (":" + XmlTypes.Get(null, null, baseTyp));

            string ptn = string.Empty;
            if (rest.pattern.Count() > 0)
            {
                ptn = rest.pattern.FirstOrDefault().value;
            }
            else
            {
                var min = (null != rest.minLength.FirstOrDefault()) ? int.Parse(rest.minLength.FirstOrDefault().Content.value) : 0;
                var max = (null != rest.maxLength.FirstOrDefault()) ? int.Parse(rest.maxLength.FirstOrDefault().Content.value) : int.MaxValue;

                if (min != 0 || max != int.MaxValue)
                    ptn = string.Format(".*{{{0},{1}}}", min, max);
            }

            return string.Concat(typ,
                string.IsNullOrEmpty(ptn) ? WriteEnum(rest) :
                    string.Format("<{0}>", ptn));
        }

        private static string WriteEnum(restriction rest)
        {
            ind.In();

            // first build a list of enumerations
            var enums = rest.enumeration.Select(enm =>
                string.Concat(ind.Tabs, enm.Content.value,
                        (string.IsNullOrEmpty(enm.Content.id) ? string.Empty :
                            (" = " + enm.Content.id))));

            // concat them into the formatted output
            var str = string.Concat("Enum {", ind.nl,
                JoinLines(enums.ToArray()), ind.nl, ind.Tabs, "}");

            ind.Out();

            return (enums.Count() == 0) ? string.Empty : str;
        }

        internal static string WriteComplexType(complexTypeType content)
        {
            ind.In();
            var ext = content.complexContent.extension;

            var lines = null == ext.@base ? new string[]
            {
                " {",
                WriteChoice(content.choice),
                WriteElements(false, content.sequence.Content.element.Select(e=>(elementType)e)),
                WriteAttributes(content.attribute),
                ind.Tabs + "}"
            } : new string[]
            {
                " : " + ext.@base + " {",
                    WriteChoice(content.complexContent.extension.choice),
                    WriteElements(false, ext.sequence.Content.element.Select(e=>(elementType)e)),
                    WriteAttributes(ext.attribute),
                ind.Tabs + "}"
            };

            ind.Out();

            return (lines.Count() <= 2) ? string.Empty : JoinLines(lines);
        }

        private static string WriteChoice(choice choice)
        {
            if (null == choice || null == choice.Content.element || choice.Content.element.Count() == 0)
                return string.Empty;

            var tabSav = ind.Tabs;
            ind.In();
            var choiceOut = JoinLines(new string[] {
                string.Concat(tabSav, "Choice {"),
                WriteElements(false, choice.Content.element.Select(e=>(elementType)e)),
                ind.Tabs + "}" + WriteMinMaxOccurs(choice.Content.minOccurs, choice.Content.maxOccurs)
            });
            ind.Out();
            return choiceOut;
        }

        private static string JoinLines(params string[] lines)
        {
            return string.Join(ind.nl, lines.Where(q => !string.IsNullOrEmpty(q)).ToArray());
        }

        private static string WriteAttributes(IList<attributeType> attr)
        {
            return string.Join(ind.nl,
                attr.Select(a => ind.Tabs +
                    string.Format("{2}{0} {1}", a.name, XmlTypes.Get(a.simpleType, null, a.type),
                        ("required" == a.use) ? '!' : '@')).ToArray());
        }

        private static string WriteElements(bool doubleNewline, IEnumerable<elementType> elems)
        {
            return string.Join((doubleNewline ? ind.nl + ind.nl : ind.nl),
                elems.Select(e => string.Concat(
                    ind.Tabs,
                    null == e.@ref ? string.Format("{0} {1}", e.name, XmlTypes.Get(e.simpleType, e.complexType, e.type)) :
                        string.Format("{0} {0}", e.@ref),
                    WriteMinMaxOccurs(e.minOccurs, e.maxOccurs))
                ).ToArray());
        }

        private static string WriteMinMaxOccurs(decimal min, object max)
        {
            var hasMin = 1 != min;
            var hasMax = (null != max && "1" != max.ToString());

            if (!hasMax && !hasMin)
                return string.Empty;

            return string.Format("[{0}-{1}]",
                hasMin ? min : 1,
                hasMax ? ("unbounded" == max.ToString() ? "n" : max) : "1");
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer Big Company
United States United States
My professional career began as a developer fixing bugs on Microsoft Word97 and I've been fixing bad habits ever since. Now I do R&D work writing v1 line of business applications mostly in C#/.Net.

I've been an avid pilot/instructor for 13+ years, I've built two airplanes and mostly fly gliders now for fun. I commute in an all-electric 1986 BMW 325 conversion.

I'd like to get back to my academic roots of programming 3D analysis applications to organize complex systems.

Comments and Discussions