Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I use XML schemas? #10

Open
rwols opened this issue Nov 27, 2020 · 2 comments
Open

How do I use XML schemas? #10

rwols opened this issue Nov 27, 2020 · 2 comments

Comments

@rwols
Copy link
Member

rwols commented Nov 27, 2020

As a relative noob with respect to XML schemas (DTD files?), how do I set up this language server to recognize, for instance, tmPreferences files?

@deathaxe
Copy link
Collaborator

It works pretty much the same way like jsonschema. I guess jsonschema even copied the methodology from xml.

In order to validate an XML file against a scheme constraints need to be added to the XML document, pointing to the scheme.

Variant 1 (DTD)

The first way to do that is a doctype definition such as <!DOCTYPE rootNodeName PUBLIC "ID" "URL"> The ID is basically the URL which identifies the doctype definition to use - same as JSON scheme. The URL points to a local or network location to the scheme file.

In case of tmPreferences, which is a property list, a valid SGML head would need to look like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

LemMinX downloads the scheme file to cache and uses that for validation then.

To support validation for files without that DOCTYPE defintion LSP-lemminx allows to create a mapping for file extensions -> schemes pretty much like LSP-json. That's what LSP-lemminx uses to assign ST's preferences file the PropertyList-1.0.dtd scheme to. The result is pretty much the same.

"xml.fileAssociations": [
	{
		"pattern": "**/*.hidden-theme",
		"systemId": "https://www.apple.com/DTDs/PropertyList-1.0.dtd"
	},
	{
		"pattern": "**/*.sublime-snippet",
		"systemId": "https://www.apple.com/DTDs/PropertyList-1.0.dtd"
	},
	{
		"pattern": "**/*.tmPreferences",
		"systemId": "https://www.apple.com/DTDs/PropertyList-1.0.dtd"
	},
	{
		"pattern": "**/*.tmTheme",
		"systemId": "https://www.apple.com/DTDs/PropertyList-1.0.dtd"
	}
],

Variant 2 (XSD)

An XML file may contain tags of several namespaces. The xmlscheme namespace <xs:...> is one example. The root node may contain a scheme definition for each namespace used in the file.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> defines all tags of <xs:> namespace being validated against the XML scheme identified by http://www.w3.org/2001/XMLSchema.

This is the more modern and flexibal approach of defining constraints in a xml file, which was created when limitations of DTD approach came up. That's why you might find both definition types for some xml file types. The xmlscheme for instance may be validated using a xmlschema.dtd or xmlschema.xsd

The rest is the same. LemMinX tries to resolve the URL and download the scheme behind to cache directory and uses it for validation and completions etc.

Catalogs (Local Scheme Definitions)

Creating our own schemes and assign them to tmPreference is what catalog.xml may be used for. Catalogs may be used to map/redirect DTD's PUPLIC, SYSTEM keys or XSD's URIs to local files.

Means we could create an XSD or DTD for tmPreferences, use the xml.fileAssociations to point them to a user defined Id, which is defined in the catalog.xml to point to our local/shipped scheme file.

The files look different, but it's the same as with jsonscheme.

I started playing with such a local catalog definition which includes the most basic schemes.

A main catalog in Catalogs/ sub directory

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD XML Catalogs V1.1//EN"
                         "http://www.oasis-open.org/committees/entity/release/1.1/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
  <nextCatalog catalog="jsp/catalog.xml"/>
  <nextCatalog catalog="plist/catalog.xml"/>
  <nextCatalog catalog="svg/catalog.xml"/>
  <nextCatalog catalog="xinclude/catalog.xml"/>
  <nextCatalog catalog="xlink/catalog.xml"/>
  <nextCatalog catalog="xml/catalog.xml"/>
  <nextCatalog catalog="xmlschema/catalog.xml"/>
  <nextCatalog catalog="xmltransform/catalog.xml"/>
</catalog>

pointing to the different schemes organized in sub directores

e.g.: Catalogs/xml/

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
			 "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
  <uri name="http://www.w3.org/XML/1998/namespace" uri="xml.xsd"/>
  <uri name="http://www.w3.org/2001" uri="xml2001.xsd"/>
  <uri name="http://www.w3.org/2004" uri="xml2004.xsd"/>
  <uri name="http://www.w3.org/2005" uri="xml2005.xsd"/>
  <uri name="http://www.w3.org/2007" uri="xml2007.xsd"/>
</catalog>

I symlinked the Catalog from Packages/LSP-lemminx/Catalog to Package Storage/LSP-lemminx/Catalog as it will need to be extracted from a sublime-package file to be readable by the language server.

The location is specified in LSP-lemminx.sublime-settings .

       "xml.catalogs": [
           "$storage_path/LSP-lemminx/catalogs/catalog.xml"
       ]

@rwols
Copy link
Member Author

rwols commented Nov 29, 2020

Thanks for this great explanation. This could perhaps go into the readme?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants