diff --git a/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini b/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini
index 9928477..801ba32 100644
--- a/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini
+++ b/administrator/components/com_jedchecker/language/en-GB/en-GB.com_jedchecker.ini
@@ -93,3 +93,18 @@ COM_JEDCHECKER_EMPTY_UPLOAD_FIELD="Please, select a zipped file to be uploaded"
COM_JEDCHECKER_TOOLBAR_CHECK="Check"
COM_JEDCHECKER_TOOLBAR_CLEAR="Clear"
COM_JEDCHECKER_CLICK_TO_VIEW_DETAILS="Click to View Details"
+COM_JEDCHECKER_MANIFEST="XML Manifests"
+COM_JEDCHECKER_MANIFEST_DESC="Validation of extension's XML manifest file"
+COM_JEDCHECKER_MANIFEST_UNKNOWN_TYPE="Unknown extension type: %s"
+COM_JEDCHECKER_MANIFEST_TYPE_NOT_ACCEPTED="Extension type '%s' is not accepted by JED"
+COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE="Node <%1$s> has unknown attribute '%2$s'"
+COM_JEDCHECKER_MANIFEST_UNKNOWN_CHILDREN="Node <%s> has unknown child element"
+COM_JEDCHECKER_MANIFEST_MISSED_REQUIRED="Node <%1$s> doesn't contain required <%2$s> element"
+COM_JEDCHECKER_MANIFEST_MISSED_OPTIONAL="Node <%1$s> doesn't contain optional <%2$s> element"
+COM_JEDCHECKER_MANIFEST_MULTIPLE_FOUND="Node <%1$s> contains multiple <%2$s> elements"
+COM_JEDCHECKER_MANIFEST_UNKNOWN_CHILD="Node <%1$s> contains unknown <%2$s> element"
+COM_JEDCHECKER_MANIFEST_EMPTY_CHILD="Found empty <%s> element"
+COM_JEDCHECKER_MANIFEST_MENU_UNUSED_ATTRIBUTE="Menu item attribute '%s' is not used with 'link' attribute"
+COM_JEDCHECKER_MANIFEST_MISSED_METHOD_UPGRADE="Without the method="upgrade" attribute the extension package cannot be upgraded"
+COM_JEDCHECKER_MANIFEST_MISSED_ATTRIBUTE="The node <%1$s> doesn't contain required '%2$s' attribute"
+COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE_VALUE="The node <%1$s> has attribute '%2$s' with unknown value "%3$s""
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest.php b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest.php
new file mode 100644
index 0000000..5d4f119
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest.php
@@ -0,0 +1,404 @@
+basedir, '\.xml$', true, true);
+
+ // Iterate through all the xml files
+ foreach ($files as $file)
+ {
+ // Try to check the file
+ $this->find($file);
+ }
+ }
+
+ /**
+ * Reads a file and validate XML manifest
+ *
+ * @param string $file - The path to the file
+ *
+ * @return boolean True if the manifest file was found, otherwise False.
+ */
+ protected function find($file)
+ {
+ $xml = simplexml_load_file($file);
+
+ // Failed to parse the xml file.
+ // Assume that this is not a extension manifest
+ if (!$xml)
+ {
+ return false;
+ }
+
+ // Check if this is an extension manifest
+ if ($xml->getName() !== 'extension')
+ {
+ return false;
+ }
+
+ // Check extension type
+ $type = (string) $xml['type'];
+
+ if (!in_array($type, $this->joomlaTypes, true))
+ {
+ $this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_TYPE', $type));
+
+ return true;
+ }
+
+ // JED allows components, modules, plugins, and packages (as a container) only
+ if (!in_array($type, $this->jedTypes, true))
+ {
+ $this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_TYPE_NOT_ACCEPTED', $type));
+ }
+
+ // Load DTD-like data for this extension type
+ $jsonFilename = __DIR__ . '/xmlmanifest/dtd_' . $type . '.json';
+
+ if (!is_file($jsonFilename))
+ {
+ return true;
+ }
+
+ // Warn if method="upgrade" attribute is not found
+ if ((string) $xml['method'] !== 'upgrade')
+ {
+ $this->report->addWarning($file, JText::_('COM_JEDCHECKER_MANIFEST_MISSED_METHOD_UPGRADE'));
+ }
+
+ // Check 'client' attribute is "site" or "administrator" (for module/template only)
+ if ($type === 'module' || $type === 'template')
+ {
+ $client = (string) $xml['client'];
+
+ if (!isset($xml['client']))
+ {
+ $this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_ATTRIBUTE', $xml->getName(), 'client'));
+ }
+ elseif ($client !== 'site' && $client !== 'administrator')
+ {
+ $this->report->addError($file, JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE_VALUE', $xml->getName(), 'client', $client));
+ }
+ }
+
+ $data = json_decode(file_get_contents($jsonFilename), true);
+ $this->DTDNodeRules = $data['nodes'];
+ $this->DTDAttrRules = $data['attributes'];
+
+ $this->errors = array();
+ $this->warnings = array();
+ $this->infos = array();
+
+ // Validate manifest
+ $this->validateXml($xml, 'extension');
+
+ if (count($this->errors))
+ {
+ $this->report->addError($file, implode('
', $this->errors));
+ }
+
+ if (count($this->warnings))
+ {
+ $this->report->addWarning($file, implode('
', $this->warnings));
+ }
+
+ if (count($this->infos))
+ {
+ $this->report->addInfo($file, implode('
', $this->infos));
+ }
+
+ // All checks passed. Return true
+ return true;
+ }
+
+ /**
+ * @param SimpleXMLElement $node XML node object
+ * @param string $ruleset rulest name in the DTD array
+ *
+ * @return void
+ */
+ protected function validateXml($node, $ruleset)
+ {
+ // Get node name
+ $name = $node->getName();
+
+ // Check attributes
+ $DTDattributes = isset($this->DTDAttrRules[$ruleset]) ? $this->DTDAttrRules[$ruleset] : array();
+
+ if (count($DTDattributes) === 0)
+ {
+ // No known attributes for this node
+ foreach ($node->attributes() as $attr)
+ {
+ $this->infos[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE', $name, (string) $attr->getName());
+ }
+ }
+ elseif ($DTDattributes[0] !== '*') // Skip node with arbitrary attributes (e.g. "field")
+ {
+ foreach ($node->attributes() as $attr)
+ {
+ $attrName = (string) $attr->getName();
+
+ if (!in_array($attrName, $DTDattributes, true))
+ {
+ // The node has unknown attribute
+ $this->infos[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_ATTRIBUTE', $name, $attrName);
+ }
+ }
+ }
+
+ // Check children nodes
+ $DTDchildRules = isset($this->DTDNodeRules[$ruleset]) ? $this->DTDNodeRules[$ruleset] : array();
+
+ // Child node name to ruleset name mapping
+ $DTDchildToRule = array();
+
+ if (count($DTDchildRules) === 0)
+ {
+ // No known children for this node
+ if ($node->count() > 0)
+ {
+ $this->infos[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_CHILDREN', $name);
+ }
+ }
+ elseif (!isset($DTDchildRules['*'])) // Skip node with arbitrary children
+ {
+ // 1) check required single elements
+ foreach ($DTDchildRules as $childRuleset => $mode)
+ {
+ $child = $childRuleset;
+
+ if (strpos($child, ':') !== false)
+ {
+ // Split ruleset name into a prefix and the child node name
+ list ($prefix, $child) = explode(':', $child, 2);
+ }
+
+ // Populate node-to-ruleset mapping
+ $DTDchildToRule[$child] = $childRuleset;
+
+ $count = $node->$child->count();
+
+ switch ($mode)
+ {
+ case '!':
+ if ($count === 0)
+ {
+ // The node doesn't contain required child element
+ $this->errors[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_REQUIRED', $name, $child);
+ }
+ elseif ($count > 1)
+ {
+ // The node contains multiple child elements when single only is expected
+ $this->errors[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_MULTIPLE_FOUND', $name, $child);
+ }
+
+ break;
+
+ case '=':
+ if ($count === 0)
+ {
+ // The node doesn't contain optional child element
+ $this->infos[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_MISSED_OPTIONAL', $name, $child);
+ }
+ elseif ($count > 1)
+ {
+ // The node contains multiple child elements when single only is expected
+ $this->warnings[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_MULTIPLE_FOUND', $name, $child);
+ }
+
+ break;
+ }
+ }
+
+ // 2) check unknown/multiple elements
+
+ // Collect unique child node names
+ $childNames = array();
+
+ foreach ($node as $child)
+ {
+ $childNames[$child->getName()] = 1;
+ }
+
+ $childNames = array_keys($childNames);
+
+ foreach ($childNames as $child)
+ {
+ if (!isset($DTDchildToRule[$child]))
+ {
+ // The node contains unknown child element
+ $this->infos[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_UNKNOWN_CHILD', $name, $child);
+ }
+ else
+ {
+ if ($DTDchildRules[$DTDchildToRule[$child]] === '?' && $node->$child->count() > 1)
+ {
+ // The node contains multiple child elements when single only is expected
+ $this->errors[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_MULTIPLE_FOUND', $name, $child);
+ }
+ }
+ }
+
+ // 3) check empty elements
+ foreach ($node as $child)
+ {
+ if ($child->count() === 0 && $child->attributes()->count() === 0 && (string) $child === '')
+ {
+ $this->infos[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_EMPTY_CHILD', $child->getName());
+ }
+ }
+ }
+
+ // Extra checks (if exist)
+ $method = 'validateXml' . $name;
+
+ if (method_exists($this, $method))
+ {
+ $this->$method($node);
+ }
+
+ // Recursion
+ foreach ($node as $child)
+ {
+ $childName = $child->getName();
+
+ if (isset($DTDchildToRule[$childName]))
+ {
+ $this->validateXml($child, $DTDchildToRule[$childName]);
+ }
+ }
+ }
+
+ /**
+ * Extra check for menu nodes
+ * @param SimpleXMLElement $node XML node
+ *
+ * @return void
+ */
+ protected function validateXmlMenu($node)
+ {
+ if (isset($node['link']))
+ {
+ // The "link" attribute overrides any other link-related attributes (warn if they present)
+ $skipAttrs = array('act', 'controller', 'layout', 'sub', 'task', 'view');
+
+ foreach ($node->attributes() as $attr)
+ {
+ $attrName = $attr->getName();
+
+ if (in_array($attrName, $skipAttrs, true))
+ {
+ $this->warnings[] = JText::sprintf('COM_JEDCHECKER_MANIFEST_MENU_UNUSED_ATTRIBUTE', $attrName);
+ }
+ }
+ }
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_component.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_component.json
new file mode 100644
index 0000000..5ca36f4
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_component.json
@@ -0,0 +1,120 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "element": "?",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "scriptfile": "?",
+ "install": "?",
+ "update": "?",
+ "uninstall": "?",
+ "files": "?",
+ "languages": "?",
+ "media": "?",
+ "administration": "?",
+ "updateservers": "?",
+ "dlid": "?",
+ "config": "?",
+ "namespace": "?"
+ },
+ "administration": {
+ "menu": "?",
+ "submenu": "?",
+ "files": "=",
+ "languages": "?",
+ "media": "?"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "media": {
+ "filename": "*",
+ "media:file": "*",
+ "folder": "*"
+ },
+ "submenu": {
+ "menu": "*"
+ },
+ "install": {
+ "sql": "*"
+ },
+ "update": {
+ "sql": "*",
+ "schemas": "*"
+ },
+ "uninstall": {
+ "sql": "*"
+ },
+ "sql": {
+ "file": "*"
+ },
+ "schemas": {
+ "schemapath": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "media": [
+ "destination",
+ "folder"
+ ],
+ "menu": [
+ "act",
+ "controller",
+ "hidden",
+ "img",
+ "layout",
+ "link",
+ "sub",
+ "task",
+ "view"
+ ],
+ "file": [
+ "charset",
+ "driver"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "namespace": [
+ "path"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_file.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_file.json
new file mode 100644
index 0000000..902338e
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_file.json
@@ -0,0 +1,86 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "scriptfile": "?",
+ "install": "?",
+ "update": "?",
+ "uninstall": "?",
+ "fileset": "!",
+ "languages": "?",
+ "updateservers": "?",
+ "dlid": "?"
+ },
+ "fileset": {
+ "files": "*"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "install": {
+ "sql": "*"
+ },
+ "update": {
+ "sql": "*",
+ "schemas": "*"
+ },
+ "uninstall": {
+ "sql": "*"
+ },
+ "sql": {
+ "file": "*"
+ },
+ "schemas": {
+ "schemapath": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder",
+ "target"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "file": [
+ "charset",
+ "driver"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_language.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_language.json
new file mode 100644
index 0000000..ad20a0b
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_language.json
@@ -0,0 +1,68 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "tag": "!",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "files": "!",
+ "media": "?",
+ "fonts": "?",
+ "update": "?",
+ "updateservers": "?",
+ "dlid": "?"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "media": {
+ "filename": "*",
+ "media:file": "*",
+ "folder": "*"
+ },
+ "fonts": {
+ "filename": "*",
+ "fonts:file": "*",
+ "folder": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "media": [
+ "destination",
+ "folder"
+ ],
+ "fonts": [
+ "folder"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_library.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_library.json
new file mode 100644
index 0000000..b886e4f
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_library.json
@@ -0,0 +1,95 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "libraryname": "!",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "packager": "?",
+ "packagerurl": "?",
+ "scriptfile": "?",
+ "install": "?",
+ "update": "?",
+ "uninstall": "?",
+ "files": "?",
+ "languages": "?",
+ "media": "?",
+ "updateservers": "?",
+ "dlid": "?"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "media": {
+ "filename": "*",
+ "media:file": "*",
+ "folder": "*"
+ },
+ "install": {
+ "sql": "*"
+ },
+ "update": {
+ "sql": "*",
+ "schemas": "*"
+ },
+ "uninstall": {
+ "sql": "*"
+ },
+ "sql": {
+ "file": "*"
+ },
+ "schemas": {
+ "schemapath": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "media": [
+ "destination",
+ "folder"
+ ],
+ "file": [
+ "charset",
+ "driver"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_module.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_module.json
new file mode 100644
index 0000000..3becd97
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_module.json
@@ -0,0 +1,144 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "element": "?",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "scriptfile": "?",
+ "install": "?",
+ "update": "?",
+ "uninstall": "?",
+ "files": "?",
+ "languages": "?",
+ "media": "?",
+ "updateservers": "?",
+ "dlid": "?",
+ "config": "?",
+ "namespace": "?"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "media": {
+ "filename": "*",
+ "media:file": "*",
+ "folder": "*"
+ },
+ "install": {
+ "sql": "*"
+ },
+ "update": {
+ "sql": "*",
+ "schemas": "*"
+ },
+ "uninstall": {
+ "sql": "*"
+ },
+ "sql": {
+ "file": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ },
+ "config": {
+ "fields": "!"
+ },
+ "fields": {
+ "fieldset": "+"
+ },
+ "fieldset": {
+ "field": "+"
+ },
+ "field": {
+ "*": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "filename": [
+ "module"
+ ],
+ "files:file": [
+ "module"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "media": [
+ "destination",
+ "folder"
+ ],
+ "file": [
+ "charset",
+ "driver"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "namespace": [
+ "path"
+ ],
+ "config": [
+ "addfieldpath",
+ "addfieldprefix",
+ "addformpath",
+ "addformprefix",
+ "addrulepath",
+ "addruleprefix"
+ ],
+ "fields": [
+ "addfieldpath",
+ "addfieldprefix",
+ "addformpath",
+ "addformprefix",
+ "addrulepath",
+ "addruleprefix",
+ "name"
+ ],
+ "fieldset": [
+ "addfieldpath",
+ "addfieldprefix",
+ "addformpath",
+ "addformprefix",
+ "addrulepath",
+ "addruleprefix",
+ "description",
+ "label",
+ "name"
+ ],
+ "field": [
+ "*"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_package.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_package.json
new file mode 100644
index 0000000..f9a7930
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_package.json
@@ -0,0 +1,76 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "packagename": "!",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "scriptfile": "?",
+ "update": "?",
+ "files": "?",
+ "languages": "?",
+ "updateservers": "?",
+ "dlid": "?",
+ "url": "?",
+ "packager": "?",
+ "packagerurl": "?",
+ "blockChildUninstall": "?"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "files:file": [
+ "client",
+ "group",
+ "id",
+ "type"
+ ],
+ "filename": [
+ "client",
+ "group",
+ "id",
+ "type"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_plugin.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_plugin.json
new file mode 100644
index 0000000..1b5b555
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_plugin.json
@@ -0,0 +1,145 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "element": "?",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "scriptfile": "?",
+ "install": "?",
+ "update": "?",
+ "uninstall": "?",
+ "files": "?",
+ "languages": "?",
+ "media": "?",
+ "updateservers": "?",
+ "dlid": "?",
+ "config": "?",
+ "namespace": "?"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "media": {
+ "filename": "*",
+ "media:file": "*",
+ "folder": "*"
+ },
+ "install": {
+ "sql": "*"
+ },
+ "update": {
+ "sql": "*",
+ "schemas": "*"
+ },
+ "uninstall": {
+ "sql": "*"
+ },
+ "sql": {
+ "file": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ },
+ "config": {
+ "fields": "!"
+ },
+ "fields": {
+ "fieldset": "+"
+ },
+ "fieldset": {
+ "field": "+"
+ },
+ "field": {
+ "*": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "group",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "filename": [
+ "plugin"
+ ],
+ "files:file": [
+ "plugin"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "media": [
+ "destination",
+ "folder"
+ ],
+ "file": [
+ "charset",
+ "driver"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "namespace": [
+ "path"
+ ],
+ "config": [
+ "addfieldpath",
+ "addfieldprefix",
+ "addformpath",
+ "addformprefix",
+ "addrulepath",
+ "addruleprefix"
+ ],
+ "fields": [
+ "addfieldpath",
+ "addfieldprefix",
+ "addformpath",
+ "addformprefix",
+ "addrulepath",
+ "addruleprefix",
+ "name"
+ ],
+ "fieldset": [
+ "addfieldpath",
+ "addfieldprefix",
+ "addformpath",
+ "addformprefix",
+ "addrulepath",
+ "addruleprefix",
+ "description",
+ "label",
+ "name"
+ ],
+ "field": [
+ "*"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}
diff --git a/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_template.json b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_template.json
new file mode 100644
index 0000000..dbceb31
--- /dev/null
+++ b/administrator/components/com_jedchecker/libraries/rules/xmlmanifest/dtd_template.json
@@ -0,0 +1,119 @@
+{
+ "nodes": {
+ "extension": {
+ "name": "!",
+ "element": "?",
+ "creationDate": "=",
+ "author": "=",
+ "authorEmail": "=",
+ "authorUrl": "=",
+ "copyright": "=",
+ "version": "!",
+ "description": "=",
+ "license": "?",
+ "scriptfile": "?",
+ "install": "?",
+ "update": "?",
+ "uninstall": "?",
+ "files": "?",
+ "images": "?",
+ "css": "?",
+ "languages": "?",
+ "media": "?",
+ "positions": "=",
+ "updateservers": "?",
+ "dlid": "?",
+ "config": "?"
+ },
+ "positions": {
+ "position": "*"
+ },
+ "files": {
+ "filename": "*",
+ "files:file": "*",
+ "folder": "*"
+ },
+ "images": {
+ "filename": "*",
+ "images:file": "*",
+ "folder": "*"
+ },
+ "css": {
+ "filename": "*",
+ "css:file": "*",
+ "folder": "*"
+ },
+ "languages": {
+ "language": "*"
+ },
+ "media": {
+ "filename": "*",
+ "media:file": "*",
+ "folder": "*"
+ },
+ "install": {
+ "sql": "*"
+ },
+ "update": {
+ "sql": "*",
+ "schemas": "*"
+ },
+ "uninstall": {
+ "sql": "*"
+ },
+ "sql": {
+ "file": "*"
+ },
+ "schemas": {
+ "schemapath": "*"
+ },
+ "updateservers": {
+ "server": "*"
+ }
+ },
+ "attributes": {
+ "extension": [
+ "client",
+ "method",
+ "overwrite",
+ "type",
+ "version"
+ ],
+ "files": [
+ "folder"
+ ],
+ "images": [
+ "folder"
+ ],
+ "css": [
+ "folder"
+ ],
+ "languages": [
+ "folder"
+ ],
+ "language": [
+ "client",
+ "tag"
+ ],
+ "position": [
+ "value"
+ ],
+ "media": [
+ "destination",
+ "folder"
+ ],
+ "file": [
+ "charset",
+ "driver"
+ ],
+ "server": [
+ "name",
+ "priority",
+ "type"
+ ],
+ "dlid": [
+ "prefix",
+ "suffix"
+ ]
+ }
+}