fonttools / fonttools

A library to manipulate font files from Python.
MIT License
4.37k stars 455 forks source link

DTD for Designspace 5? #2735

Open jenskutilek opened 2 years ago

jenskutilek commented 2 years ago

Is there a DTD file for designspace 5 anywhere? It would make authoring DS files easier.

jenskutilek commented 2 years ago

This is what I've come up with so far. Partly autogenerated, and manually extended to match all my VF project. No guarantees ;)

<!ELEMENT designspace (axes,rules?,sources,variable-fonts?,instances?,lib?)>
<!ATTLIST designspace format NMTOKEN #REQUIRED>

<!ELEMENT axes (axis+)>
<!ATTLIST axes elidedfallbackname NMTOKEN #IMPLIED>

<!ELEMENT axis (labelname*,labels*,map*)>
<!ATTLIST axis tag NMTOKEN #REQUIRED>
<!ATTLIST axis name NMTOKEN #REQUIRED>
<!ATTLIST axis minimum NMTOKEN #IMPLIED>
<!ATTLIST axis maximum NMTOKEN #IMPLIED>
<!ATTLIST axis default NMTOKEN #REQUIRED>
<!ATTLIST axis values CDATA #IMPLIED>

<!ELEMENT labelname (#PCDATA)>
<!ATTLIST labelname xml:lang NMTOKEN #IMPLIED>

<!ELEMENT labels (label+)>
<!ATTLIST labels ordering NMTOKEN #REQUIRED>

<!ELEMENT label (labelname*)>
<!ATTLIST label uservalue NMTOKEN #REQUIRED>
<!ATTLIST label userminimum NMTOKEN #IMPLIED>
<!ATTLIST label usermaximum NMTOKEN #IMPLIED>
<!ATTLIST label name ID #REQUIRED>
<!ATTLIST label elidable NMTOKEN #IMPLIED>
<!ATTLIST label linkeduservalue NMTOKEN #IMPLIED>

<!ELEMENT map EMPTY>
<!ATTLIST map input NMTOKEN #REQUIRED>
<!ATTLIST map output NMTOKEN #REQUIRED>

<!ELEMENT rules (rule+)>
<!ATTLIST rules processing CDATA #IMPLIED>

<!ELEMENT rule (conditionset+,sub+)>
<!ATTLIST rule name CDATA #REQUIRED>

<!ELEMENT conditionset (condition+)>

<!ELEMENT condition EMPTY>
<!ATTLIST condition name CDATA #REQUIRED>
<!ATTLIST condition maximum CDATA #REQUIRED>
<!ATTLIST condition minimum CDATA #REQUIRED>

<!ELEMENT sub EMPTY>
<!ATTLIST sub name CDATA #REQUIRED>
<!ATTLIST sub with CDATA #REQUIRED>

<!ELEMENT sources (source+)>

<!ELEMENT source (features?,groups?,info?,lib?,location)>
<!ATTLIST source familyname CDATA #IMPLIED>
<!ATTLIST source filename CDATA #REQUIRED>
<!ATTLIST source name CDATA #IMPLIED>
<!ATTLIST source stylename CDATA #IMPLIED>

<!ELEMENT location (dimension+)>
<!ELEMENT groups EMPTY><!ATTLIST groups copy NMTOKEN #IMPLIED>
<!ELEMENT features EMPTY><!ATTLIST features copy NMTOKEN #IMPLIED>
<!ELEMENT kerning EMPTY><!ATTLIST kerning copy NMTOKEN #IMPLIED>
<!ELEMENT info EMPTY><!ATTLIST info copy NMTOKEN #IMPLIED>

<!ELEMENT dimension EMPTY>
<!ATTLIST dimension name CDATA #REQUIRED>
<!ATTLIST dimension xvalue NMTOKEN #REQUIRED>

<!ELEMENT variable-fonts (variable-font+)>
<!ELEMENT variable-font (axis-subsets)>
<!ATTLIST variable-font name NMTOKEN #REQUIRED>

<!ELEMENT axis-subsets (axis-subset+)>

<!ELEMENT axis-subset EMPTY>
<!ATTLIST axis-subset name NMTOKEN #REQUIRED>
<!ATTLIST axis-subset uservalue NMTOKEN #IMPLIED>

<!ELEMENT instances (instance+)>

<!ELEMENT instance (location,kerning?,info?,lib?)>
<!ATTLIST instance familyname CDATA #IMPLIED>
<!ATTLIST instance filename CDATA #IMPLIED>
<!ATTLIST instance name CDATA #IMPLIED>
<!ATTLIST instance postscriptfontname ID #IMPLIED>
<!ATTLIST instance stylemapfamilyname CDATA #IMPLIED>
<!ATTLIST instance stylemapstylename CDATA #IMPLIED>
<!ATTLIST instance stylename CDATA #IMPLIED>

<!ELEMENT lib (dict?)>
<!ATTLIST lib copy NMTOKEN #IMPLIED>

<!-- from https://www.apple.com/DTDs/PropertyList-1.0.dtd -->
<!ENTITY % plistObject "(array|data|date|dict|real|integer|string|true|false)">

<!ELEMENT array (%plistObject;)*>
<!ELEMENT dict (key,%plistObject;)*>
<!ELEMENT key (#PCDATA)>

<!ELEMENT string (#PCDATA)>
<!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded -->
<!ELEMENT date (#PCDATA)> <!-- Contents should conform to a subset of ISO 8601 (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'.  Smaller units may be omitted with a loss of precision) -->

<!-- Numerical primitives -->
<!ELEMENT true EMPTY>  <!-- Boolean constant true -->
<!ELEMENT false EMPTY> <!-- Boolean constant false -->
<!ELEMENT real (#PCDATA)> <!-- Contents should represent a floating point number matching ("+" | "-")? d+ ("."d*)? ("E" ("+" | "-") d+)? where d is a digit 0-9.  -->
<!ELEMENT integer (#PCDATA)> <!-- Contents should represent a (possibly signed) integer number in base 10 -->
anthrotype commented 2 years ago

thanks Jens. Would be nice to integrate this in the code, maybe we can have a validate method that uses lxml to validate against the DTD (e.g. https://stackoverflow.com/a/31769680). The DTD in theory could even be embedded in the xml file's DOCTYPE.. Not sure, maybe it's sufficient to have it in fonttools. Perhaps .dtd file added as package_data and included in the distribution.

anthrotype commented 2 years ago

It would make authoring DS files easier.

curious, how so?

jenskutilek commented 2 years ago

VSCode does live validation and autosuggests valid attributes when you link an XML file to a DTD like so:

Bildschirmfoto 2022-10-13 um 15 55 27

anthrotype commented 2 years ago

cool! how do you link an XML file with a .dtd with vscode?

anthrotype commented 2 years ago

oh I see now you added a DOCTYPE declaration with the path to your .dtd

jenskutilek commented 2 years ago

Yep. There are several options to connect a DTD with a file.

jenskutilek commented 2 years ago

I'm checking my file against the designspace specs again, and will look for a place to add it in fontTools.

madig commented 2 years ago

Where could we put the DTD file so we can easily reference them in Designspace files?