Add XML validation XSD files
authorChristian Weiske <cweiske@cweiske.de>
Wed, 17 Jan 2018 20:10:02 +0000 (21:10 +0100)
committerChristian Weiske <cweiske@cweiske.de>
Wed, 17 Jan 2018 20:10:02 +0000 (21:10 +0100)
tools/database.xsd [new file with mode: 0644]
tools/info.xsd [new file with mode: 0644]

diff --git a/tools/database.xsd b/tools/database.xsd
new file mode 100644 (file)
index 0000000..33c61c7
--- /dev/null
@@ -0,0 +1,320 @@
+<?xml version="1.0"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           elementFormDefault="qualified" attributeFormDefault="unqualified">
+    <xs:element name="database">
+        <xs:annotation>
+            <xs:documentation>Database definition. These xml files were once
+                used for MDB2 which was a major source of bugs and
+                unmaintained. To keep compatibility the xml files definitions
+                are now parsed and used to create Doctrine schemas. To trigger
+                a database migration you need to increase your version number
+                in your info.xml file
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="name" type="non-empty-string" minOccurs="0"
+                            maxOccurs="1">
+                    <xs:annotation>
+                        <xs:documentation>Value is ignored</xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+                <xs:element name="create" type="xs:boolean" minOccurs="0"
+                            maxOccurs="1">
+                    <xs:annotation>
+                        <xs:documentation>Value is ignored</xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+                <xs:element name="overwrite" type="xs:boolean" minOccurs="0"
+                            maxOccurs="1">
+                    <xs:annotation>
+                        <xs:documentation>Value is ignored</xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+                <xs:element name="charset" type="non-empty-string"
+                            minOccurs="0"
+                            maxOccurs="1">
+                    <xs:annotation>
+                        <xs:documentation>Value is ignored</xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+                <xs:element name="table" type="table" minOccurs="1"
+                            maxOccurs="unbounded">
+                    <xs:annotation>
+                        <xs:documentation>Each table contains a full database
+                            table
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+
+    <!-- basic types -->
+    <xs:simpleType name="non-empty-string">
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="table">
+        <xs:sequence>
+            <xs:element name="name" type="non-empty-string" minOccurs="1"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Table name. You can and should use
+                        *dbprefix* before your table, e.g.
+                        *dbprefix*news_items. The value will be replaced with a
+                        configurable prefix and defaults to "oc_"
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="create" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Value is ignored</xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="overwrite" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Value is ignored</xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="charset" type="non-empty-string" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Value is ignored</xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="declaration" type="declaration" minOccurs="1"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Contains the actual database columns and
+                        indices
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="declaration">
+        <xs:sequence>
+            <xs:element name="field" type="field" minOccurs="0"
+                        maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation>A list of columns</xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="index" type="index" minOccurs="0"
+                        maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation>A list of indices on that table
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="field">
+        <xs:sequence>
+            <xs:element name="name" type="non-empty-string" minOccurs="1"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Column name</xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="type" type="field-type" minOccurs="1"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Column types. Certain types like integer
+                        (aka smallint, integer, bigint), clob (aka text), text
+                        (aka string), timestamp (aka datetime) and numeric (aka
+                        decimal) are special to Nextcloud and will be
+                        translated to their doctrine equivalents. Everything
+                        else will be sent as is to doctrines type system. See
+                        http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html
+                        for a list of all types
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="length" type="xs:int" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Length of the type. This will not only
+                        define how long your text columns aka VARCHARs will be
+                        set but also determine the size of the integer field:
+                        &lt; 4 will be transformed to smallint, 4 will be
+                        transformed to integer and &gt; 4 will be transformed
+                        to bigint
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="unsigned" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Can only be set for numeric values like
+                        float, integer, etc. and will make them unsigned
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="notnull" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>If a value should never be null
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="autoincrement" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Can only be set for primary keys
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="default" type="xs:string" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Default value if given. Can also be empty
+                        in which case the default will be an empty string.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="comments" type="non-empty-string" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Doctrine comment, can be ignored
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="primary" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>True for the primary key. For composed
+                        primary keys use a unique index.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="precision" type="xs:int" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Total number of digits for a
+                        numerics/decimal type including decimal digits, e.g.
+                        precision 3 and scale 2 will only allow 3.21 but not
+                        23.21
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="scale" type="xs:int" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Scale for a numeric/decimal type, e.g. 2
+                        will save decimals with two decimal places: 3.21
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:simpleType name="field-type">
+        <xs:restriction base="xs:string">
+            <!-- smallint and bigint are set by setting a length smaller or bigger than 4 -->
+            <xs:enumeration value="integer"/>
+            <!-- clob equals text -->
+            <xs:enumeration value="clob"/>
+            <!-- text equals string -->
+            <xs:enumeration value="text"/>
+            <!-- timestamp equals datetime -->
+            <xs:enumeration value="timestamp"/>
+            <!-- numeric equals decimal -->
+            <xs:enumeration value="numeric"/>
+            <!-- doctrine types minus Nextcloud mappings-->
+            <xs:enumeration value="smallint"/>
+            <xs:enumeration value="bigint"/>
+            <xs:enumeration value="decimal"/>
+            <xs:enumeration value="float"/>
+            <xs:enumeration value="string"/>
+            <xs:enumeration value="text"/>
+            <xs:enumeration value="guid"/>
+            <xs:enumeration value="binary"/>
+            <xs:enumeration value="blob"/>
+            <xs:enumeration value="boolean"/>
+            <xs:enumeration value="date"/>
+            <xs:enumeration value="datetime"/>
+            <xs:enumeration value="datetimetz"/>
+            <xs:enumeration value="time"/>
+            <xs:enumeration value="dateinterval"/>
+            <xs:enumeration value="json"/>
+            <!-- object and arrays are not covered since support is bad -->
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="index">
+        <xs:annotation>
+            <xs:documentation>Element for defining indices. Can also be used to
+                define composite primary keys: simply add more than one field
+                to an index and define it as unique
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="name" type="non-empty-string" minOccurs="1"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Index name. Should be unique
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="primary" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>True if the index is in fact a primary
+                        key. Will be ignored if the primary key is already set
+                        in the field section
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="unique" type="xs:boolean" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>If the index for the field or combination
+                        of fields should be unique
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="field" type="index-field" minOccurs="1"
+                        maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation>List of index fields that are used to
+                        create the index
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="index-field">
+        <xs:sequence>
+            <xs:element name="name" type="non-empty-string" minOccurs="1"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Name of the column that should be
+                        indexed
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="sorting" type="index-sorting" minOccurs="0"
+                        maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>Value is ignored</xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:simpleType name="index-sorting">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="ascending"/>
+            <xs:enumeration value="descending"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/tools/info.xsd b/tools/info.xsd
new file mode 100644 (file)
index 0000000..efd6d2d
--- /dev/null
@@ -0,0 +1,627 @@
+<?xml version="1.0"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+    <xs:element name="info">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="id" type="id" minOccurs="1" maxOccurs="1"/>
+                <xs:element name="name" type="l10n-string" minOccurs="1"
+                            maxOccurs="unbounded"/>
+                <xs:element name="summary" type="l10n-string" minOccurs="1"
+                            maxOccurs="unbounded"/>
+                <xs:element name="description" type="l10n-text" minOccurs="1"
+                            maxOccurs="unbounded"/>
+                <xs:element name="version" type="semver"
+                            minOccurs="1" maxOccurs="1"/>
+                <xs:element name="licence" type="licence" minOccurs="1"
+                            maxOccurs="unbounded"/>
+                <xs:element name="author" type="author" minOccurs="1"
+                            maxOccurs="unbounded"/>
+                <xs:element name="namespace" type="limited-string"
+                            minOccurs="0" maxOccurs="1"/>
+                <xs:element name="types" type="types" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="documentation" type="documentation"
+                            minOccurs="0" maxOccurs="1"/>
+                <xs:element name="category" type="category" minOccurs="1"
+                            maxOccurs="unbounded"/>
+                <xs:element name="website" type="url" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="discussion" type="url" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="bugs" type="url" minOccurs="1"
+                            maxOccurs="1"/>
+                <xs:element name="repository" type="repository" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="screenshot" type="screenshot" minOccurs="0"
+                            maxOccurs="10"/>
+                <xs:element name="dependencies" type="dependencies"
+                            minOccurs="1" maxOccurs="1"/>
+                <xs:element name="background-jobs" type="jobs"
+                            minOccurs="0" maxOccurs="1"/>
+                <xs:element name="repair-steps" type="repair-steps"
+                            minOccurs="0" maxOccurs="1"/>
+                <xs:element name="two-factor-providers"
+                            type="two-factor-providers"
+                            minOccurs="0" maxOccurs="1"/>
+                <xs:element name="commands" type="commands"
+                            minOccurs="0" maxOccurs="1"/>
+                <xs:element name="settings" type="settings" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="activity" type="activity" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="navigations" type="navigations" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="contactsmenu" type="contactsmenu" minOccurs="0"
+                            maxOccurs="1"/>
+                <xs:element name="collaboration" type="collaboration" minOccurs="0"
+                            maxOccurs="1" />
+                <xs:element name="sabre" type="sabre" minOccurs="0"
+                            maxOccurs="1" />
+            </xs:sequence>
+        </xs:complexType>
+        <xs:unique name="uniqueNameL10n">
+            <xs:selector xpath="name"/>
+            <xs:field xpath="@lang"/>
+        </xs:unique>
+        <xs:unique name="uniqueSummaryL10n">
+            <xs:selector xpath="summary"/>
+            <xs:field xpath="@lang"/>
+        </xs:unique>
+        <xs:unique name="uniqueDescriptionL10n">
+            <xs:selector xpath="description"/>
+            <xs:field xpath="@lang"/>
+        </xs:unique>
+        <xs:unique name="uniqueLicense">
+            <xs:selector xpath="licence"/>
+            <xs:field xpath="."/>
+        </xs:unique>
+        <xs:unique name="uniqueTypes">
+            <xs:selector xpath="types/type"/>
+            <xs:field xpath="."/>
+        </xs:unique>
+        <xs:unique name="uniqueCategory">
+            <xs:selector xpath="category"/>
+            <xs:field xpath="."/>
+        </xs:unique>
+        <xs:unique name="uniqueDatabase">
+            <xs:selector xpath="dependencies/database"/>
+            <xs:field xpath="."/>
+        </xs:unique>
+        <xs:unique name="uniqueLib">
+            <xs:selector xpath="dependencies/lib"/>
+            <xs:field xpath="."/>
+        </xs:unique>
+        <xs:unique name="uniqueCommand">
+            <xs:selector xpath="dependencies/command"/>
+            <xs:field xpath="."/>
+        </xs:unique>
+    </xs:element>
+
+    <!-- basic types -->
+    <xs:simpleType name="empty-string">
+        <xs:restriction base="xs:string">
+            <xs:maxLength value="0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="non-empty-string">
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="limited-string">
+        <xs:restriction base="non-empty-string">
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="l10n-text">
+        <xs:simpleContent>
+            <xs:extension base="non-empty-string">
+                <xs:attribute name="lang" type="l10n-code" default="en"
+                              use="optional"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="l10n-string">
+        <xs:simpleContent>
+            <xs:restriction base="l10n-text">
+                <xs:maxLength value="128"/>
+            </xs:restriction>
+        </xs:simpleContent>
+    </xs:complexType>
+
+
+    <xs:simpleType name="l10n-code">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="af"/>
+            <xs:enumeration value="ar"/>
+            <xs:enumeration value="ast"/>
+            <xs:enumeration value="az"/>
+            <xs:enumeration value="bg"/>
+            <xs:enumeration value="be"/>
+            <xs:enumeration value="bn"/>
+            <xs:enumeration value="br"/>
+            <xs:enumeration value="bs"/>
+            <xs:enumeration value="ca"/>
+            <xs:enumeration value="cs"/>
+            <xs:enumeration value="cy"/>
+            <xs:enumeration value="da"/>
+            <xs:enumeration value="de"/>
+            <xs:enumeration value="el"/>
+            <xs:enumeration value="en"/>
+            <xs:enumeration value="eo"/>
+            <xs:enumeration value="es"/>
+            <xs:enumeration value="es-ar"/>
+            <xs:enumeration value="es-co"/>
+            <xs:enumeration value="es-mx"/>
+            <xs:enumeration value="es-ni"/>
+            <xs:enumeration value="es-ve"/>
+            <xs:enumeration value="et"/>
+            <xs:enumeration value="eu"/>
+            <xs:enumeration value="fa"/>
+            <xs:enumeration value="fi"/>
+            <xs:enumeration value="fr"/>
+            <xs:enumeration value="fy"/>
+            <xs:enumeration value="ga"/>
+            <xs:enumeration value="gd"/>
+            <xs:enumeration value="gl"/>
+            <xs:enumeration value="he"/>
+            <xs:enumeration value="hi"/>
+            <xs:enumeration value="hr"/>
+            <xs:enumeration value="hu"/>
+            <xs:enumeration value="ia"/>
+            <xs:enumeration value="id"/>
+            <xs:enumeration value="io"/>
+            <xs:enumeration value="is"/>
+            <xs:enumeration value="it"/>
+            <xs:enumeration value="ja"/>
+            <xs:enumeration value="ka"/>
+            <xs:enumeration value="kk"/>
+            <xs:enumeration value="km"/>
+            <xs:enumeration value="kn"/>
+            <xs:enumeration value="ko"/>
+            <xs:enumeration value="lb"/>
+            <xs:enumeration value="lt"/>
+            <xs:enumeration value="lv"/>
+            <xs:enumeration value="mk"/>
+            <xs:enumeration value="ml"/>
+            <xs:enumeration value="mn"/>
+            <xs:enumeration value="mr"/>
+            <xs:enumeration value="my"/>
+            <xs:enumeration value="nb"/>
+            <xs:enumeration value="ne"/>
+            <xs:enumeration value="nl"/>
+            <xs:enumeration value="nn"/>
+            <xs:enumeration value="os"/>
+            <xs:enumeration value="pa"/>
+            <xs:enumeration value="pl"/>
+            <xs:enumeration value="pt"/>
+            <xs:enumeration value="pt-br"/>
+            <xs:enumeration value="ro"/>
+            <xs:enumeration value="ru"/>
+            <xs:enumeration value="sk"/>
+            <xs:enumeration value="sl"/>
+            <xs:enumeration value="sq"/>
+            <xs:enumeration value="sr"/>
+            <xs:enumeration value="sr-latn"/>
+            <xs:enumeration value="sv"/>
+            <xs:enumeration value="sw"/>
+            <xs:enumeration value="ta"/>
+            <xs:enumeration value="te"/>
+            <xs:enumeration value="th"/>
+            <xs:enumeration value="tr"/>
+            <xs:enumeration value="tt"/>
+            <xs:enumeration value="udm"/>
+            <xs:enumeration value="uk"/>
+            <xs:enumeration value="ur"/>
+            <xs:enumeration value="vi"/>
+            <xs:enumeration value="zh-hans"/>
+            <xs:enumeration value="zh-hant"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="semver">
+        <xs:restriction base="limited-string">
+            <xs:pattern
+                    value="(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="version">
+        <xs:restriction base="limited-string">
+            <xs:pattern value="[0-9]+(\.[0-9]+){0,2}"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="url">
+        <xs:restriction base="xs:anyURI">
+            <xs:pattern value="https?://.+"/>
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="secure-url">
+        <xs:restriction base="xs:anyURI">
+            <xs:pattern value="https://.+"/>
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="email">
+        <xs:restriction base="limited-string">
+            <xs:pattern value="[^@]+@[^\.]+\..+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- first level elements -->
+    <xs:complexType name="screenshot">
+        <xs:simpleContent>
+            <xs:extension base="secure-url">
+                <xs:attribute name="small-thumbnail" use="optional"
+                              type="secure-url"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="id">
+        <xs:restriction base="limited-string">
+            <xs:pattern value="[a-z]+[a-z0-9_]*[a-z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="author">
+        <xs:simpleContent>
+            <xs:extension base="limited-string">
+                <xs:attribute name="mail" type="email" use="optional"/>
+                <xs:attribute name="homepage" type="url" use="optional"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="repository">
+        <xs:simpleContent>
+            <xs:extension base="url">
+                <xs:attribute name="type" type="vcs" use="optional"
+                              default="git"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="vcs">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="git"/>
+            <xs:enumeration value="mercurial"/>
+            <xs:enumeration value="subversion"/>
+            <xs:enumeration value="bzr"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="types">
+        <xs:sequence>
+            <xs:element name="prelogin" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="filesystem" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="authentication" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="logging" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="dav" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="prevent_group_restriction" minOccurs="0"
+                        maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:simpleType name="category">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="security"/>
+            <xs:enumeration value="customization"/>
+            <xs:enumeration value="files"/>
+            <xs:enumeration value="integration"/>
+            <xs:enumeration value="monitoring"/>
+            <xs:enumeration value="multimedia"/>
+            <xs:enumeration value="office"/>
+            <xs:enumeration value="organization"/>
+            <xs:enumeration value="social"/>
+            <xs:enumeration value="tools"/>
+            <xs:enumeration value="games"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="licence">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="agpl"/>
+            <xs:enumeration value="mpl"/>
+            <xs:enumeration value="apache"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="databases">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="sqlite"/>
+            <xs:enumeration value="mysql"/>
+            <xs:enumeration value="pgsql"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="documentation">
+        <xs:sequence>
+            <xs:element name="user" type="url" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="admin" type="url" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="developer" type="url" minOccurs="0"
+                        maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="settings">
+        <xs:sequence>
+            <xs:element name="admin" type="php-class" minOccurs="0"
+                        maxOccurs="unbounded"/>
+            <xs:element name="admin-section" type="php-class" minOccurs="0"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="activity">
+        <xs:sequence>
+            <xs:element name="settings" type="activity-settings" minOccurs="0"
+                        maxOccurs="1"/>
+            <xs:element name="filters" type="activity-filters" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="providers" type="activity-providers" minOccurs="0"
+                        maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="activity-settings">
+        <xs:sequence>
+            <xs:element name="setting" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="activity-filters">
+        <xs:sequence>
+            <xs:element name="filter" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="activity-providers">
+        <xs:sequence>
+            <xs:element name="provider" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="navigations">
+        <xs:sequence>
+            <xs:element name="navigation" type="navigation" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="navigation">
+        <xs:sequence>
+            <xs:element name="id" type="id" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="name" type="non-empty-string" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="route" type="route" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="icon" type="xs:anyURI" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="order" type="xs:int" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="type" type="navigation-type" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute name="role" type="navigation-role" default="all" use="optional"/>
+    </xs:complexType>
+
+    <xs:simpleType name="navigation-role">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="all"/>
+            <xs:enumeration value="admin"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="navigation-type">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="link"/>
+            <xs:enumeration value="settings"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="route">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="[0-9a-zA-Z_]+(\.[0-9a-zA-Z_]+){2}"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="contactsmenu">
+        <xs:sequence>
+            <xs:element name="provider" type="php-class" minOccurs="1"
+                        maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="collaboration">
+        <xs:sequence>
+            <xs:element name="plugins" type="collaboration-plugins" minOccurs="0" maxOccurs="1">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="collaboration-plugins">
+        <xs:sequence>
+            <xs:element name="plugin" type="collaboration-plugins-plugin" minOccurs="1" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="collaboration-plugins-plugin">
+        <xs:simpleContent>
+            <xs:extension base="php-class">
+                <xs:attribute name="type" type="collaboration-plugin-type" use="required"/>
+                <xs:attribute name="share-type" type="share-type" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="collaboration-plugin-type">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="collaborator-search"/>
+            <xs:enumeration value="autocomplete-sort"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="sabre">
+        <xs:sequence>
+            <xs:element name="collections" type="sabre-collections" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="plugins" type="sabre-plugins" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="sabre-collections">
+        <xs:sequence>
+            <xs:element name="collection" type="php-class" minOccurs="1" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="sabre-plugins">
+        <xs:sequence>
+            <xs:element name="plugin" type="php-class" minOccurs="1" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:simpleType name="share-type">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="SHARE_TYPE_USER"/>
+            <xs:enumeration value="SHARE_TYPE_GROUP"/>
+            <xs:enumeration value="SHARE_TYPE_LINK"/>
+            <xs:enumeration value="SHARE_TYPE_EMAIL"/>
+            <xs:enumeration value="SHARE_TYPE_CONTACT"/>
+            <xs:enumeration value="SHARE_TYPE_REMOTE"/>
+            <xs:enumeration value="SHARE_TYPE_CIRCLE"/>
+            <xs:enumeration value="SHARE_TYPE_GUEST"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- dependencies -->
+    <xs:complexType name="dependencies">
+        <xs:sequence>
+            <xs:element name="php" type="php" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="database" type="database" minOccurs="0"
+                        maxOccurs="unbounded"/>
+            <xs:element name="command" type="shell-command" minOccurs="0"
+                        maxOccurs="unbounded"/>
+            <xs:element name="lib" type="min-max-version" minOccurs="0"
+                        maxOccurs="unbounded"/>
+            <xs:element name="owncloud" type="owncloud" minOccurs="0"
+                        maxOccurs="1"/>
+            <xs:element name="nextcloud" type="nextcloud" minOccurs="1"
+                        maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="owncloud">
+        <xs:attribute name="min-version" type="version" use="required"/>
+        <xs:attribute name="max-version" type="version" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="nextcloud">
+        <xs:attribute name="min-version" type="version" use="required"/>
+        <xs:attribute name="max-version" type="version" use="required"/>
+    </xs:complexType>
+
+    <xs:simpleType name="shell-command">
+        <xs:restriction base="limited-string">
+            <xs:pattern value="[a-zA-Z\-_]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="min-max-version">
+        <xs:simpleContent>
+            <xs:extension base="limited-string">
+                <xs:attribute name="min-version" type="version"
+                              use="optional"/>
+                <xs:attribute name="max-version" type="version"
+                              use="optional"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="database">
+        <xs:simpleContent>
+            <xs:extension base="databases">
+                <xs:attribute name="min-version" type="version"
+                              use="optional"/>
+                <xs:attribute name="max-version" type="version"
+                              use="optional"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="php">
+        <xs:simpleContent>
+            <xs:extension base="empty-string">
+                <xs:attribute name="min-int-size" type="bits" use="optional"
+                              default="32"/>
+                <xs:attribute name="min-version" type="version"
+                              use="optional"/>
+                <xs:attribute name="max-version" type="version"
+                              use="optional"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="bits">
+        <xs:restriction base="xs:int">
+            <xs:enumeration value="32"/>
+            <xs:enumeration value="64"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="repair-steps">
+        <xs:sequence>
+            <xs:element name="pre-migration" type="steps" minOccurs="0"
+                        maxOccurs="1"/>
+            <xs:element name="post-migration" type="steps" minOccurs="0"
+                        maxOccurs="1"/>
+            <xs:element name="live-migration" type="steps" minOccurs="0"
+                        maxOccurs="1"/>
+            <xs:element name="install" type="steps" minOccurs="0"
+                        maxOccurs="1"/>
+            <xs:element name="uninstall" type="steps" minOccurs="0"
+                        maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="jobs">
+        <xs:sequence>
+            <xs:element name="job" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="steps">
+        <xs:sequence>
+            <xs:element name="step" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="two-factor-providers">
+        <xs:sequence>
+            <xs:element name="provider" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="commands">
+        <xs:sequence>
+            <xs:element name="command" type="php-class" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:simpleType name="php-class">
+        <xs:restriction base="xs:string">
+            <xs:pattern
+                    value="[a-zA-Z_][0-9a-zA-Z_]*(\\[a-zA-Z_][0-9a-zA-Z_]*)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+</xs:schema>