XML DTD for the package configuration file

Isaac Jones ijones at syntaxpolice.org
Wed Oct 15 01:54:50 EDT 2003


This is my first attempt at an XML DTD.  Does anyone have any
suggestions for good XML references either a book or a web site?
Google seems to be suffering from too much XML information.  Is there
a Haddock / Javadoc type way to notate a DTD?  Should I be using
schemas?  Are they overkill?  What do you think of the style?
Sometimes I have trouble choosing between using an attribute, and
using a nested element.  For instance:

<envitem><var>x</var><val>y</val></envitem>

verses

<envitem var="x">y</envitem>

Here's a shot at a DTD for the packages configuration file and an
example config file that validates with the DTD (I used xmllint
--noout --valid) and the Haskell datatype that it's meant to reflect.
I expect it will change a lot as I learn more about XML and about
packaging, but I wanted to get it out there in case I'm going horribly
wrong somehow.

I'm not really satisfied with the version stuff or the versionrange
stuff (mostly the Haskell code).

Slight background for people who know less about xml than me: a DTD is
a means of verifying that an XML file has the correct structure.  It
seems rather limited in that there are no types, and the regular
expressions are weaker than one might expect (I can't say "the data in
this field should correspond to the following regexp).  XML Schemas
seem to fix some of these problems.  But DTDs seem to be a nice way to
document and share information about the format of an XML file.

peace,

isaac

------------------------------------------------------------
Packages.dtd
------------------------------------------------------------
-- CUT HERE --
<!ELEMENT packageconf (package+)>
<!ATTLIST packageconf version CDATA #REQUIRED>

<!-- package -->
<!ELEMENT package (version?,importdirs?,sourcedirs?,librarydirs?,hslibraries?,extralibraries?,depends?,builddepends?,ccopts?,ldopts?,environment?,graftpoint?,extraframeworks?)>
<!ATTLIST package version CDATA #IMPLIED>

<!ATTLIST package name CDATA #REQUIRED>
<!ATTLIST package auto (false | true) "false">

<!ELEMENT packageident (#PCDATA)>

<!-- Path related -->
<!ELEMENT filepath (#PCDATA)>
<!ELEMENT sourcedirs (filepath+)>
<!ELEMENT importdirs (filepath+)>
<!ELEMENT librarydirs (filepath+)>

<!-- Libraries -->
<!ELEMENT hslibraries (library+)>
<!ELEMENT cincludes (include+)>
<!ELEMENT extralibraries (library+)>
<!ELEMENT library (#PCDATA)>
<!ELEMENT include (#PCDATA)>

<!-- Options -->
<!ELEMENT ccopts (option+)>
<!ELEMENT ldopts (option+)>
<!ELEMENT option (#PCDATA)>
<!ATTLIST option type (short | long | verbatim) "verbatim">

<!-- Depends -->
<!ELEMENT builddepends (dependency+)>
<!ELEMENT depends      (dependency+)>

<!ELEMENT dependency   (versionrange?)>
<!ATTLIST dependency name CDATA #REQUIRED>
<!ATTLIST dependency version CDATA #IMPLIED>

<!-- Documentation -->
<!ELEMENT haddockhtmlroot  (#PCDATA)>
<!ELEMENT haddockinterface (#PCDATA)>

<!-- Versioning -->
<!ELEMENT versionrange (version,version?)> <!-- second one is for range -->
<!ATTLIST versionrange type (any | orlater | exactly | orearlier | between) "orlater">

<!-- I'm not exactly satisfied with this. I should also be able to say <= -->
<!-- and >=, but these are already pretty verbose. -->

<!ELEMENT version (numberversion | simpleversion | dateversion)>
<!ELEMENT numberversion (major?,minor?,patch?)>
<!ELEMENT simpleversion (#PCDATA)>

<!ELEMENT major (#PCDATA)>
<!ELEMENT minor (#PCDATA)>
<!ELEMENT patch (#PCDATA)>

<!ELEMENT dateversion (year,month?,day?,patch?)>
<!ELEMENT year  (#PCDATA)>
<!ELEMENT month (#PCDATA)>
<!ELEMENT day   (#PCDATA)>
<!-- Simpleversions should be a fixed format: 1.2.3-4 or so -->

<!-- Environment -->
<!ELEMENT environment (envitem+)>
<!ELEMENT envitem (var,val)+>
<!ELEMENT var (#PCDATA)>
<!ELEMENT val (#PCDATA)>
<!--        Or maybe this would be preferred? -->
<!--        <envitem> var="boing">boo</envitem> -->

<!-- Misc -->
<!ELEMENT graftpoint (#PCDATA)>
<!ELEMENT extraframeworks (framework+)>
<!ELEMENT framework (#PCDATA)>
-- CUT HERE --

------------------------------------------------------------
Packages.xml
------------------------------------------------------------
-- CUT HERE --
<?xml version="1.0"?>
<!DOCTYPE packageconf  SYSTEM "Packages.dtd">
<packageconf version="0.1">
  <package name="packageName" version="1.0" auto="true">
    <importdirs><filepath>/foo</filepath>
                <filepath>/foo/bar/bang</filepath></importdirs>
    <sourcedirs><filepath>/foo</filepath>
                <filepath>/foo/bar/bang</filepath></sourcedirs>

    <graftpoint>System.IO</graftpoint>
  </package>
<!-- ============================== -->
  <package name="dependExample" version="3">
     <builddepends>
        <dependency name="otherPkg">
          <versionrange type="exactly">
	    <version><simpleversion>3.4.5-6</simpleversion></version>
	  </versionrange>
        </dependency>

        <dependency name="otherPkg2">
          <versionrange type="orlater">
	    <version><dateversion><year>1998</year></dateversion></version>
	  </versionrange>
        </dependency>

	<dependency name="otherPkg3" version="2.0.0-0" />

        <dependency name="otherPkg3">
          <versionrange type="between">
	    <version><simpleversion>3.3</simpleversion></version>
	    <version><simpleversion>3.5</simpleversion></version>
	  </versionrange>
        </dependency>

     </builddepends>
  </package>
<!-- ============================== -->
  <package name="optionExample">
     <version><numberedversion><major>10</major>
                               <minor>11</minor>
                               <patch>12</patch></numberedversion></version>
     <ccopts>
         <option type="short">b</option>
         <option type="long">foo</option>
         <option type="verbatim">--bar</option>
         <option>--bang</option>
     </ccopts>

     <environment>
       <envitem><var>foo</var><val>bar</val></envitem>
       <envitem><var>bang</var><val>baz</val></envitem>
     </environment>
  </package>
</packageconf>
-- CUT HERE --
------------------------------------------------------------
Package Config data structure
------------------------------------------------------------
-- CUT HERE --
data PkgIdentifier
    = PkgIdentifier {pkgName::String, pkgVersion::Version}
{- ^Often need name and version since multiple versions of a single
    package can exist on a system. -}

data PackageConfig
   = Package {
        pkgIdent        :: PkgIdentifier,
        license         :: License,
        auto            :: Bool,
<!--         provides        :: [String], -->
<!-- {- ^A bit pie-in-the-sky; might indicate that this package provides -->
<!--     functionality that other packages also provide, such as a compiler -->
<!--     or GUI framework, and upon which other packages might depend. -} -->

<!--         isDefault       :: Bool, -->
<!-- -- ^might indicate if this is the default compiler or GUI framework. -->
<!-- think through isDefault more, maybe we actually want a list of defaults -->

        import_dirs     :: [FilePath],
        source_dirs     :: [FilePath],
        library_dirs    :: [FilePath],
        include_dirs    :: [FilePath],
        hs_libraries    :: [String],
        extra_libraries :: [String],
        c_includes      :: [String],
        build_deps      :: [Dependency], -- build dependencies
        depends         :: [Dependency], -- use dependencies
<!--         extra_ghc_opts  :: [String], -->
        extra_cc_opts   :: [String],
        extra_ld_opts   :: [String],
        framework_dirs  :: [String],
        haddock_html_root :: String,
        haddock_interface :: String,
        default_grafting_point :: String,
-- ^Related to new packages proposal
        vars            :: [(String, String)],
-- ^Variable, value pairs, whatever author wants here
        extra_frameworks:: [String]}

data Version = DateVersion {versionYear  :: Integer,
                            versionMonth :: Month,
                            versionDay   :: Integer}
             | NumberedVersion {versionMajor      :: Integer,
                                versionMinor      :: Integer,
                                versionPatchLevel :: Integer}

data License = GPL | LGPL | BSD | {- ... | -} OtherLicense FilePath

data Dependency = Dependency String VersionRange

data VersionRange
  = AnyVersion
  | OrLaterVersion     Version
  | ExactlyThisVersion Version
  | OrEarlierVersion   Version

type PackageMap = FiniteMap PkgIdentifier PackageConfig
-- CUT HERE --


More information about the Libraries mailing list