mdmodels 0.2.10

A tool to generate models, code and schemas from markdown files
Documentation
{#
    Non-empty iff any attribute is serialized as an XML child element (truthy for {% if %}).
#}
{%- macro has_elements(attributes) -%}
    {%- for attribute in attributes -%}
        {%- if attribute.xml.is_attr is false -%}x{%- endif -%}
    {%- endfor -%}
{%- endmacro -%}

{#
    use="required" on xs:attribute (mutually exclusive with default in XSD 1.0).
#}
{%- macro is_required(attribute) -%}
    {%- if attribute.required is true %} use="required"{%- endif -%}
{%- endmacro -%}

{#
    default= only when optional; required attributes cannot carry default per XSD 1.0.
#}
{%- macro get_default(attr) -%}
    {%- if 'default' in attr and attr.required is not true %} default="{{ xml_escape(attr.default) }}"{%- endif -%}
{%- endmacro -%}

{#
    Cardinality for repeatable elements (optional 0..* vs required 1..*).
#}
{%- macro is_multiple(attribute) -%}
    {%- if attribute.multiple is true -%}
        {%- if attribute.required is true %} minOccurs="1" maxOccurs="unbounded"{%- else %} minOccurs="0" maxOccurs="unbounded"{%- endif -%}
    {%- endif -%}
{%- endmacro -%}

{#
    Attribute/element base type: user-defined vs xs: built-in.
#}
{%- macro is_reference(attribute) -%}
    {%- if attribute.dtypes[0] in object_names or attribute.dtypes[0] in enum_names -%}
        {{ attribute.dtypes[0] }}Type
    {%- else -%}
        xs:{{ attribute.dtypes[0] }}
    {%- endif -%}
{%- endmacro -%}

{%- macro create_attribute(attribute) -%}
        {%- if attribute.docstring | length > 0 %}
        <xs:attribute name="{{ attribute.name }}" type="{{ is_reference(attribute) }}"
            {%- if is_required(attribute) %} {{ is_required(attribute) }}{%- endif -%}
            {%- if get_default(attribute) %} {{ get_default(attribute) }}{%- endif -%}
            >
            <xs:annotation>
                <xs:documentation>
                    {{ wrap(xml_escape(attribute.docstring), 70, "", "                    ", None) }}
                </xs:documentation>
            </xs:annotation>
        </xs:attribute>
        {%- else -%}
        <xs:attribute name="{{ attribute.name }}" type="{{ is_reference(attribute) }}"
        {%- if is_required(attribute) %} {{ is_required(attribute) }}{%- endif -%}
        {%- if get_default(attribute) %} {{ get_default(attribute) }}{%- endif -%}
        />
        {%- endif -%}
{%- endmacro %}

{%- macro create_element(attribute) -%}
{%- if attribute.dtypes[0] in object_names or attribute.dtypes[0] in enum_names -%}

    {%- if attribute.multiple is true -%}
            <xs:element name="{{attribute.name}}">
                {%- if attribute.docstring | length > 0 %}
                <xs:annotation>
                    <xs:documentation>
                        {{ wrap(xml_escape(attribute.docstring), 70, "", "                        ", None) }}
                    </xs:documentation>
                </xs:annotation>
                {%- endif %}
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="{{attribute.dtypes[0]}}" type="{{attribute.dtypes[0]}}Type"
                        {%- if is_multiple(attribute) %}{{ is_multiple(attribute) }}{%- endif -%}
                        />
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
    {%- else -%}
            {%- if attribute.docstring | length > 0 -%}
            <xs:element name="{{attribute.name}}" type="{{attribute.dtypes[0]}}Type">
                <xs:annotation>
                    <xs:documentation>
                        {{ wrap(xml_escape(attribute.docstring), 70, "", "                        ", None) }}
                    </xs:documentation>
                </xs:annotation>
            </xs:element>
            {%- else -%}
            <xs:element name="{{attribute.name}}" type="{{attribute.dtypes[0]}}Type"/>
            {%- endif -%}
    {%- endif -%}

{%- else -%}
            {%- if attribute.docstring | length > 0 -%}
            <xs:element name="{{attribute.name}}" type="xs:{{attribute.dtypes[0]}}"
            {%- if is_multiple(attribute) %} {{ is_multiple(attribute) }}{% endif -%}
            {%- if get_default(attribute) %} {{ get_default(attribute) }}{% endif -%}
            >
                <xs:annotation>
                    <xs:documentation>
                        {{ wrap(xml_escape(attribute.docstring), 70, "", "                        ", None) }}
                    </xs:documentation>
                </xs:annotation>
            </xs:element>
            {%- else -%}
            <xs:element name="{{attribute.name}}" type="xs:{{attribute.dtypes[0]}}"
            {%- if is_multiple(attribute) %} {{ is_multiple(attribute) }}{%- endif %}
            {%- if get_default(attribute) %} {{ get_default(attribute) }}{%- endif -%}
            />
            {%- endif -%}

            {%- endif -%}
{%- endmacro %}

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <!-- Roots -->
    {%- for object in object_names %}
    <xs:element name="{{ object }}" type="{{ object }}Type"/>
    {%- endfor %}
    {% for object in objects%}
    <!-- {{ object.name }} Definition -->
    <xs:complexType name="{{ object.name }}Type">
        {%- if has_elements(object.attributes) %}
        <xs:sequence>
            {%- for attribute in object.attributes %}
            {%- if attribute.xml.is_attr is false %}
            {{ create_element(attribute) }}
            {%- endif %}
            {%- endfor %}
        </xs:sequence>
        {%- endif -%}
        {%- for attribute in object.attributes -%}
        {%- if attribute.xml.is_attr is true -%}
        {{ create_attribute(attribute) }}
        {%- endif -%}
        {%- endfor %}
    </xs:complexType>
    {% endfor %}

    {%- for enum in enums %}
    <!-- Enum {{ enum.name }} Definition -->
    <xs:simpleType name="{{ enum.name }}Type">
        <xs:restriction base="xs:string">
            {%- for key, value in enum.mappings | dictsort %}
            <xs:enumeration value="{{ xml_escape(value) }}"/>
            {%- endfor %}
        </xs:restriction>
    </xs:simpleType>
    {%- endfor %}

</xs:schema>