diff --git a/core/Command/App/CheckCode.php b/core/Command/App/CheckCode.php
index 82a137e58e1c584a9a724c90c8f45c529687bae6..a129bcf1e103e8ddb6dac0c03e45916f2d4136fc 100644
--- a/core/Command/App/CheckCode.php
+++ b/core/Command/App/CheckCode.php
@@ -44,20 +44,12 @@ use OC\App\CodeChecker\PrivateCheck;
 
 class CheckCode extends Command implements CompletionAwareInterface  {
 
-	/** @var InfoParser */
-	private $infoParser;
-
 	protected $checkers = [
 		'private' => PrivateCheck::class,
 		'deprecation' => DeprecationCheck::class,
 		'strong-comparison' => StrongComparisonCheck::class,
 	];
 
-	public function __construct(InfoParser $infoParser) {
-		parent::__construct();
-		$this->infoParser = $infoParser;
-	}
-
 	protected function configure() {
 		$this
 			->setName('app:check-code')
@@ -134,50 +126,12 @@ class CheckCode extends Command implements CompletionAwareInterface  {
 		}
 
 		if(!$input->getOption('skip-validate-info')) {
-			$infoChecker = new InfoChecker($this->infoParser);
-
-			$infoChecker->listen('InfoChecker', 'mandatoryFieldMissing', function($key) use ($output) {
-				$output->writeln("<error>Mandatory field missing: $key</error>");
-			});
-
-			$infoChecker->listen('InfoChecker', 'deprecatedFieldFound', function($key, $value) use ($output) {
-				if($value === [] || is_null($value) || $value === '') {
-					$output->writeln("<info>Deprecated field available: $key</info>");
-				} else {
-					$output->writeln("<info>Deprecated field available: $key => $value</info>");
-				}
-			});
-
-			$infoChecker->listen('InfoChecker', 'missingRequirement', function($minMax) use ($output) {
-				$output->writeln("<error>Nextcloud $minMax version requirement missing</error>");
-			});
-
-			$infoChecker->listen('InfoChecker', 'differentVersions', function($versionFile, $infoXML) use ($output) {
-				$output->writeln("<error>Different versions provided (appinfo/version: $versionFile - appinfo/info.xml: $infoXML)</error>");
+			// Can not inject because of circular dependency
+			$infoChecker = new InfoChecker(\OC::$server->getAppManager());
+			$infoChecker->listen('InfoChecker', 'parseError', function($error) use ($output) {
+				$output->writeln("<error>Invalid appinfo.xml file found: $error</error>");
 			});
 
-			$infoChecker->listen('InfoChecker', 'sameVersions', function($path) use ($output) {
-				$output->writeln("<info>Version file isn't needed anymore and can be safely removed ($path)</info>");
-			});
-
-			$infoChecker->listen('InfoChecker', 'migrateVersion', function($version) use ($output) {
-				$output->writeln("<error>Migrate the app version to appinfo/info.xml (add <version>$version</version> to appinfo/info.xml and remove appinfo/version)</error>");
-			});
-
-			if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
-				$infoChecker->listen('InfoChecker', 'mandatoryFieldFound', function($key, $value) use ($output) {
-					$output->writeln("<info>Mandatory field available: $key => $value</info>");
-				});
-
-				$infoChecker->listen('InfoChecker', 'optionalFieldFound', function($key, $value) use ($output) {
-					$output->writeln("<info>Optional field available: $key => $value</info>");
-				});
-
-				$infoChecker->listen('InfoChecker', 'unusedFieldFound', function($key, $value) use ($output) {
-					$output->writeln("<info>Unused field available: $key => $value</info>");
-				});
-			}
-
 			$infoErrors = $infoChecker->analyse($appId);
 
 			$errors = array_merge($errors, $infoErrors);
diff --git a/core/register_command.php b/core/register_command.php
index 372d775dc14aed89c66a16046ffd68752d46ab7b..578b4f799b6d17797f14927f6780ce5ab0d2b610 100644
--- a/core/register_command.php
+++ b/core/register_command.php
@@ -40,8 +40,7 @@
 $application->add(new \Stecman\Component\Symfony\Console\BashCompletion\CompletionCommand());
 $application->add(new OC\Core\Command\Status);
 $application->add(new OC\Core\Command\Check(\OC::$server->getSystemConfig()));
-$infoParser = new \OC\App\InfoParser();
-$application->add(new OC\Core\Command\App\CheckCode($infoParser));
+$application->add(new OC\Core\Command\App\CheckCode());
 $application->add(new OC\Core\Command\L10n\CreateJs());
 $application->add(new \OC\Core\Command\Integrity\SignApp(
 		\OC::$server->getIntegrityCodeChecker(),
diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php
index 0e921ba1b7ff341613205fa69cb1017915c43fb4..81037b42613b5a6e37e939c8378b2ef3ee36b9d1 100644
--- a/lib/private/App/AppManager.php
+++ b/lib/private/App/AppManager.php
@@ -411,6 +411,7 @@ class AppManager implements IAppManager {
 
 	/**
 	 * @inheritdoc
+	 * In case you change this method, also change \OC\App\CodeChecker\InfoChecker::isShipped()
 	 */
 	public function isShipped($appId) {
 		$this->loadShippedJson();
@@ -422,6 +423,10 @@ class AppManager implements IAppManager {
 		return in_array($appId, $alwaysEnabled, true);
 	}
 
+	/**
+	 * In case you change this method, also change \OC\App\CodeChecker\InfoChecker::loadShippedJson()
+	 * @throws \Exception
+	 */
 	private function loadShippedJson() {
 		if ($this->shippedApps === null) {
 			$shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
diff --git a/lib/private/App/CodeChecker/InfoChecker.php b/lib/private/App/CodeChecker/InfoChecker.php
index e8791bd703766eda2cb1c8f6156e8a111cb4a270..f5de6d376d83f50480c55385a143a3acbf8a28ad 100644
--- a/lib/private/App/CodeChecker/InfoChecker.php
+++ b/lib/private/App/CodeChecker/InfoChecker.php
@@ -23,121 +23,88 @@
 
 namespace OC\App\CodeChecker;
 
-use OC\App\InfoParser;
 use OC\Hooks\BasicEmitter;
+use OCP\App\AppPathNotFoundException;
+use OCP\App\IAppManager;
 
 class InfoChecker extends BasicEmitter {
 
-	/** @var InfoParser */
-	private $infoParser;
+	/** @var string[] */
+	private $shippedApps;
 
-	private $mandatoryFields = [
-		'author',
-		'description',
-		'dependencies',
-		'id',
-		'licence',
-		'name',
-		'version',
-	];
-	private $optionalFields = [
-		'bugs',
-		'category',
-		'default_enable',
-		'documentation',
-		'namespace',
-		'ocsid',
-		'public',
-		'remote',
-		'repository',
-		'types',
-		'website',
-	];
-	private $deprecatedFields = [
-		'info',
-		'require',
-		'requiremax',
-		'requiremin',
-		'shipped',
-		'standalone',
-	];
-
-	public function __construct(InfoParser $infoParser) {
-		$this->infoParser = $infoParser;
-	}
+	/** @var string[] */
+	private $alwaysEnabled;
 
 	/**
 	 * @param string $appId
 	 * @return array
+	 * @throws \RuntimeException
 	 */
-	public function analyse($appId) {
+	public function analyse($appId): array {
 		$appPath = \OC_App::getAppPath($appId);
 		if ($appPath === false) {
 			throw new \RuntimeException("No app with given id <$appId> known.");
 		}
 
-		$errors = [];
-
-		$info = $this->infoParser->parse($appPath . '/appinfo/info.xml');
-
-		if (!isset($info['dependencies']['nextcloud']['@attributes']['min-version'])) {
-			$errors[] = [
-				'type' => 'missingRequirement',
-				'field' => 'min',
-			];
-			$this->emit('InfoChecker', 'missingRequirement', ['min']);
-		}
-
-		if (!isset($info['dependencies']['nextcloud']['@attributes']['max-version'])) {
-			$errors[] = [
-				'type' => 'missingRequirement',
-				'field' => 'max',
-			];
-			$this->emit('InfoChecker', 'missingRequirement', ['max']);
-		}
-
-		foreach ($info as $key => $value) {
-			if(is_array($value)) {
-				$value = json_encode($value);
-			}
-			if (in_array($key, $this->mandatoryFields)) {
-				$this->emit('InfoChecker', 'mandatoryFieldFound', [$key, $value]);
-				continue;
-			}
+		$xml = new \DOMDocument();
+		$xml->load($appPath . '/appinfo/info.xml');
 
-			if (in_array($key, $this->optionalFields)) {
-				$this->emit('InfoChecker', 'optionalFieldFound', [$key, $value]);
-				continue;
+		$schema = \OC::$SERVERROOT . '/resources/app-info.xsd';
+		try {
+			if ($this->isShipped($appId)) {
+				// Shipped apps are allowed to have the public and default_enabled tags
+				$schema = \OC::$SERVERROOT . '/resources/app-info-shipped.xsd';
 			}
-
-			if (in_array($key, $this->deprecatedFields)) {
-				// skip empty arrays - empty arrays for remote and public are always added
-				if($value === '[]' && in_array($key, ['public', 'remote', 'info'])) {
-					continue;
-				}
-				$this->emit('InfoChecker', 'deprecatedFieldFound', [$key, $value]);
-				continue;
-			}
-
-			$this->emit('InfoChecker', 'unusedFieldFound', [$key, $value]);
+		} catch (\Exception $e) {
+			// Assume it is not shipped
 		}
 
-		foreach ($this->mandatoryFields as $key) {
-			if(!isset($info[$key])) {
-				$this->emit('InfoChecker', 'mandatoryFieldMissing', [$key]);
+		$errors = [];
+		if (!$xml->schemaValidate($schema)) {
+			foreach (libxml_get_errors() as $error) {
 				$errors[] = [
-					'type' => 'mandatoryFieldMissing',
-					'field' => $key,
+					'type' => 'parseError',
+					'field' => $error->message,
 				];
+				$this->emit('InfoChecker', 'parseError', [$error->message]);
 			}
 		}
 
-		$versionFile = $appPath . '/appinfo/version';
-		if (is_file($versionFile)) {
-			$version = trim(file_get_contents($versionFile));
-			$this->emit('InfoChecker', 'migrateVersion', [$version]);
-		}
-
 		return $errors;
 	}
+
+	/**
+	 * This is a copy of \OC\App\AppManager::isShipped(), keep both in sync.
+	 * This method is copied, so the code checker works even when Nextcloud is
+	 * not installed yet. The AppManager requires a database connection, which
+	 * fails in that case.
+	 *
+	 * @param string $appId
+	 * @return bool
+	 * @throws \Exception
+	 */
+	protected function isShipped(string $appId): bool {
+		$this->loadShippedJson();
+		return \in_array($appId, $this->shippedApps, true);
+	}
+
+	/**
+	 * This is a copy of \OC\App\AppManager::loadShippedJson(), keep both in sync
+	 * This method is copied, so the code checker works even when Nextcloud is
+	 * not installed yet. The AppManager requires a database connection, which
+	 * fails in that case.
+	 *
+	 * @throws \Exception
+	 */
+	protected function loadShippedJson() {
+		if ($this->shippedApps === null) {
+			$shippedJson = \OC::$SERVERROOT . '/core/shipped.json';
+			if (!file_exists($shippedJson)) {
+				throw new \Exception("File not found: $shippedJson");
+			}
+			$content = json_decode(file_get_contents($shippedJson), true);
+			$this->shippedApps = $content['shippedApps'];
+			$this->alwaysEnabled = $content['alwaysEnabled'];
+		}
+	}
 }
diff --git a/resources/app-info-shipped.xsd b/resources/app-info-shipped.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..97221d1fb9cdee68c6396d3da8b584faf97f141c
--- /dev/null
+++ b/resources/app-info-shipped.xsd
@@ -0,0 +1,671 @@
+<?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="default_enable" 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:element name="public" type="public" 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="doc-user-url">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="https://.+|user-[a-z]+[\-a-z]*[a-z]+"/>
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="doc-admin-url">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="https://.+|admin-[a-z]+[\-a-z]*[a-z]+"/>
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="doc-developer-url">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="https://.+|developer-[a-z]+[\-a-z]*[a-z]+"/>
+            <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="doc-user-url" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="admin" type="doc-admin-url" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="developer" type="doc-developer-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:element name="personal" type="php-class" minOccurs="0"
+                        maxOccurs="unbounded"/>
+            <xs:element name="personal-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>
+
+
+    <xs:complexType name="public">
+        <xs:sequence>
+            <xs:element name="webdav" type="path" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="files" type="path" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- 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:simpleType name="path">
+        <xs:restriction base="xs:string">
+            <xs:pattern
+                    value="[a-zA-Z_][0-9a-zA-Z_]*(/[a-zA-Z_][0-9a-zA-Z_]*)*\.php"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+</xs:schema>
diff --git a/resources/app-info.xsd b/resources/app-info.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..4460b0f63b9b1f1d1b7a8f5ec3a07026f6e086b9
--- /dev/null
+++ b/resources/app-info.xsd
@@ -0,0 +1,652 @@
+<?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="doc-user-url">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="https://.+|user-[a-z]+[\-a-z]*[a-z]+"/>
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="doc-admin-url">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="https://.+|admin-[a-z]+[\-a-z]*[a-z]+"/>
+            <xs:maxLength value="256"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="doc-developer-url">
+        <xs:restriction base="non-empty-string">
+            <xs:pattern value="https://.+|developer-[a-z]+[\-a-z]*[a-z]+"/>
+            <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="doc-user-url" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="admin" type="doc-admin-url" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="developer" type="doc-developer-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:element name="personal" type="php-class" minOccurs="0"
+                        maxOccurs="unbounded"/>
+            <xs:element name="personal-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>
diff --git a/tests/apps/testapp-dependency-missing/appinfo/info.xml b/tests/apps/testapp-dependency-missing/appinfo/info.xml
deleted file mode 100644
index c765400a76f61f2e6cfd4643d0593a9f0a23f9a7..0000000000000000000000000000000000000000
--- a/tests/apps/testapp-dependency-missing/appinfo/info.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<info>
-	<id>testapp-infoxml-version</id>
-	<version>1.2.3</version>
-	<author>Jane</author>
-	<description>A b c</description>
-	<licence>Abc</licence>
-	<name>Test app</name>
-</info>
diff --git a/tests/apps/testapp-infoxml/appinfo/info.xml b/tests/apps/testapp-infoxml/appinfo/info.xml
deleted file mode 100644
index d4df1c3cd3fad9856e3d0ae7d1fbaf866f9736d4..0000000000000000000000000000000000000000
--- a/tests/apps/testapp-infoxml/appinfo/info.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0"?>
-<info>
-	<id>testapp-infoxml</id>
-	<version>1.2.3</version>
-	<author>Jane</author>
-	<description>A b c</description>
-	<licence>Abc</licence>
-	<name>Test app</name>
-	<dependencies>
-		<nextcloud min-version="12.0" max-version="12.0"/>
-	</dependencies>
-</info>
diff --git a/tests/apps/testapp-name-missing/appinfo/info.xml b/tests/apps/testapp-name-missing/appinfo/info.xml
deleted file mode 100644
index 591c436189942a64ee37ed83ca67f5375a8628b8..0000000000000000000000000000000000000000
--- a/tests/apps/testapp-name-missing/appinfo/info.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0"?>
-<info>
-	<id>testapp-version</id>
-	<version>1.1.1</version>
-	<author>Jane</author>
-	<description>A b c</description>
-	<licence>Abc</licence>
-	<dependencies>
-		<nextcloud min-version="12.0" max-version="12.0"/>
-	</dependencies>
-</info>
diff --git a/tests/apps/testapp-version/appinfo/info.xml b/tests/apps/testapp-version/appinfo/info.xml
deleted file mode 100644
index 28e2475800fe1e14e549e9429c839ede308b98c3..0000000000000000000000000000000000000000
--- a/tests/apps/testapp-version/appinfo/info.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0"?>
-<info>
-	<id>testapp-version</id>
-	<author>Jane</author>
-	<description>A b c</description>
-	<licence>Abc</licence>
-	<name>Test app</name>
-	<dependencies>
-		<nextcloud min-version="12.0" max-version="12.0"/>
-	</dependencies>
-</info>
diff --git a/tests/apps/testapp-version/appinfo/version b/tests/apps/testapp-version/appinfo/version
deleted file mode 100644
index 0495c4a88caed0f036ffab0948c17d4b5fdc96c1..0000000000000000000000000000000000000000
--- a/tests/apps/testapp-version/appinfo/version
+++ /dev/null
@@ -1 +0,0 @@
-1.2.3
diff --git a/tests/apps/testapp_dependency_missing/appinfo/info.xml b/tests/apps/testapp_dependency_missing/appinfo/info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b0ca188aefc8d25a95e0d9891875a9bf45c42534
--- /dev/null
+++ b/tests/apps/testapp_dependency_missing/appinfo/info.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
+	  xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
+	<id>testapp_infoxml</id>
+	<name>Test app</name>
+	<summary>A b c</summary>
+	<description>A b c</description>
+	<version>1.2.3</version>
+	<licence>agpl</licence>
+	<author>Jane</author>
+	<category>games</category>
+	<bugs>https://example.org</bugs>
+</info>
diff --git a/tests/apps/testapp_infoxml/appinfo/info.xml b/tests/apps/testapp_infoxml/appinfo/info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b7575687fe5b8231f33dab3cdbf9f5545b5f1e60
--- /dev/null
+++ b/tests/apps/testapp_infoxml/appinfo/info.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
+	  xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
+	<id>testapp_infoxml</id>
+	<name>Test app</name>
+	<summary>A b c</summary>
+	<description>A b c</description>
+	<version>1.2.3</version>
+	<licence>agpl</licence>
+	<author>Jane</author>
+	<category>games</category>
+	<bugs>https://example.org</bugs>
+	<dependencies>
+		<nextcloud min-version="12.0" max-version="12.0"/>
+	</dependencies>
+</info>
diff --git a/tests/apps/testapp_name_missing/appinfo/info.xml b/tests/apps/testapp_name_missing/appinfo/info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..872c8752c75ce18692414b83f83697e1716106b4
--- /dev/null
+++ b/tests/apps/testapp_name_missing/appinfo/info.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
+	  xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
+	<id>testapp_name_missing</id>
+	<summary>A b c</summary>
+	<description>A b c</description>
+	<version>1.2.3</version>
+	<licence>agpl</licence>
+	<author>Jane</author>
+	<category>games</category>
+	<bugs>https://example.org</bugs>
+	<dependencies>
+		<nextcloud min-version="12.0" max-version="12.0"/>
+	</dependencies>
+</info>
diff --git a/tests/apps/testapp_version/appinfo/info.xml b/tests/apps/testapp_version/appinfo/info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3a48fccd45f430a610cb96878c7876db59171794
--- /dev/null
+++ b/tests/apps/testapp_version/appinfo/info.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
+	  xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
+	<id>testapp_version</id>
+	<name>Test app</name>
+	<summary>A b c</summary>
+	<description>A b c</description>
+	<licence>agpl</licence>
+	<author>Jane</author>
+	<category>games</category>
+	<bugs>https://example.org</bugs>
+	<dependencies>
+		<nextcloud min-version="12.0" max-version="12.0"/>
+	</dependencies>
+</info>
diff --git a/tests/lib/App/CodeChecker/InfoCheckerTest.php b/tests/lib/App/CodeChecker/InfoCheckerTest.php
index 760d988073918d5fab2a95c0440616869f7845d2..9f354a4611ca8fade1ed1f6f05e9bfb58a49a06c 100644
--- a/tests/lib/App/CodeChecker/InfoCheckerTest.php
+++ b/tests/lib/App/CodeChecker/InfoCheckerTest.php
@@ -44,19 +44,21 @@ class InfoCheckerTest extends TestCase {
 
 	protected function setUp() {
 		parent::setUp();
-		$this->infoChecker = new InfoChecker(new InfoParser());
+		$this->infoChecker = new InfoChecker(\OC::$server->getAppManager());
 	}
 
 	public function appInfoData() {
 		return [
-			['testapp-infoxml', []],
-			['testapp-version', [['type' => 'mandatoryFieldMissing', 'field' => 'version']]],
-			['testapp-dependency-missing', [
-				['type' => 'missingRequirement', 'field' => 'min'],
-				['type' => 'missingRequirement', 'field' => 'max'],
-				['type' => 'mandatoryFieldMissing', 'field' => 'dependencies'],
+			['testapp_infoxml', []],
+			['testapp_version', [
+				['type' => 'parseError', 'field' => 'Element \'licence\': This element is not expected. Expected is one of ( description, version ).' . "\n"],
+			]],
+			['testapp_dependency_missing', [
+				['type' => 'parseError', 'field' => 'Element \'info\': Missing child element(s). Expected is one of ( repository, screenshot, dependencies ).' . "\n"],
+			]],
+			['testapp_name_missing', [
+				['type' => 'parseError', 'field' => 'Element \'summary\': This element is not expected. Expected is ( name ).' . "\n"],
 			]],
-			['testapp-name-missing', [['type' => 'mandatoryFieldMissing', 'field' => 'name']]],
 		];
 	}
 
@@ -68,6 +70,7 @@ class InfoCheckerTest extends TestCase {
 	 */
 	public function testApps($appId, $expectedErrors) {
 		$errors = $this->infoChecker->analyse($appId);
+		libxml_clear_errors();
 
 		$this->assertEquals($expectedErrors, $errors);
 	}