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");
}
}
}