OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

 


 

   Relax NG With Classes

[ Lists Home | Date Index | Thread Index ]

Intro:
I trying to make a better RDF serialization, but Relax NG I also want to
use some Design Patterns from my favorite programming book [1].  As the
story goes, I spent a day and a half [2] figuring out a version of Relax
NG with classes.  I hacked together a stylesheet too, so it isn't just a
lame-idea.  Someone else might need something like this, or I made a
mistake.  So check it out please.

Grammar:
First you need a sort-of Relax NG document.  Some namespaces are defined
[3].  Note that the slash (or is it a backslash) at the end of &rwc; is
mandatory; it's there in case some gal or guy decides to talk about it
with RDF statements.  The document MUST begin with a grammar element,
and thus also contain a start element:

<grammar xmlns = "&rng;" xmlns:c = "&rwc;">
<start>
  <element name="hi">
    <text />
  </element>
</start>
</grammar>

The grammar element may also contain c:class elements.  These get name
attributes with NCName values that can't clash with the name of any
define elements in the current scope.  The c:class can contain start or
define elements - that's all of the Relax NG elements it can take.
Those defines and starts can reference each other, but not defines
outside the class.  Here's an example:

<grammar xmlns = "&rng;" xmlns:c = "&rwc;">
<start>
  <element name="hi">
    <ref name="A" />
  </element>
</start>
<c:class name="A">
  <start combine="choice">
    <ref name="foo" />
  </start>
  <define name="foo">
    <element name="foo">
      <ref name="bar" />
    </element>
  </define>
  <define name="bar">
    <attribute name="bar" />
  </define>
</c:class>
</grammar>

And the stylesheet (at end of email) should convert it to:

<grammar xmlns = "&rng;" xmlns:c = "&rwc;">
<start>
  <element name="hi">
    <ref name="A" />
  </element>
</start>
<define name="A">
  <grammar>
    <start combine="choice">
      <ref name="foo" />
    </start>
    <define name="foo">
      <element name="foo">
        <ref name="bar" />
      </element>
    </define>
    <define name="bar">
      <attribute name="bar" />
    </define>
  </grammar>
</define>
</grammar>

You can inherit definitions from other classes; this is done with the
c:inherit element, strangely enough.  :-)  Any definitions defined in
the inheritee class that have the same name as a definition in the
inheriter class are not imported (but the references still are).  An
exception is when the "combine" attribute is attached.  Here's an
example:

<grammar xmlns = "&rng;" xmlns:c = "&rwc;">
<start>
  <element name="hi">
    <ref name="A" />
  </element>
</start>
<c:class name="A">
  <c:inherit name="B" />
  <start>
    <ref name="foo" />
  </start>
  <define name="foo">
    <element name="foo">
      <ref name="bar" />
    </element>
  </define>
</c:class>
<c:class name="B">
  <define name="foo">
    <element name="goo">
      <attribute name="moo" />
      <text />
    </element>
  </define>
  <define name="bar">
    <attribute name="bar" />
  </define>
</c:class>
</grammar>

That should become:

<grammar xmlns = "&rng;" xmlns:c = "&rwc;">
<start>
  <element name="hi">
    <ref name="A" />
  </element>
</start>
<define name="A">
  <grammar>
    <define name="bar">
      <attribute name="bar" />
    </define>
    <start>
      <ref name="foo" />
    </start>
    <define name="foo">
      <element name="foo">
        <ref name="bar" />
      </element>
    </define>
  </grammar>
</define>
<define name="B">
  <grammar>
    <define name="foo">
      <element name="goo">
        <attribute name="moo" />
        <text />
      </element>
    </define>
    <define name="bar">
      <attribute name="bar" />
    </define>
  </grammar>
</define>
</grammar>

Notice that "bar" was imported from class-B but "foo" wasn't.  That's
because the definition in class-A overrides the one in class-B.
However, if a "combine" attribute is specified, both definitions will be
imported (since one could combine with the other.

Well, the final thing is the stylesheet; it is here [4] and here [5].
Note that abstract types and other doodads can be made with Relax NG
tricks.  Anyway, hope that's helpful.  Finally, if you want to email me,
use j f c s t 2 4 (shift-two) p i r e m o v e t t (period) e d u [darn
spammers!].  Make sure to fix the punctuation and get rid of the word
that means "get rid of".  Or use jimbolist at hotmail dot com (public).
No spam.

--
Jimmy Cerra

] "XML is just syntax, and you can therefore 
]  use it any way you like." - Michael Kay

[1] Design Patterns, urn:isbn:0-201-63361-2. It is by Erich Gamma,
Richard Helm, Ralph Johnson and John Vlissides.  That's a cool last
name, BTW.

[2] I'm new to XSLT (<2mo) and Relax NG (<1mo).

[3] Note that the entity:
 * &rng; should map to http://relaxng.org/ns/structure/1.0
 * &rwc; should map to
http://purl.org/jfc/2003/06/25/relax/ng/with/classes/

[4] http://purl.org/jfc/2003/06/26/test.xsl

[5] Note that some newlines were added by the email thing.

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"
  xmlns     = "http://relaxng.org/ns/structure/1.0";
  xmlns:rng = "http://relaxng.org/ns/structure/1.0";
  xmlns:xsl = "http://www.w3.org/1999/XSL/Transform";
  xmlns:c   = "http://purl.org/jfc/2003/06/25/relax/ng/with/classes/";>
  <xsl:variable name="rngwc"
select="'http://purl.org/jfc/2003/06/25/relax/ng/with/classes/'" />


  <xsl:template match="/">
    <xsl:apply-templates />
  </xsl:template>


  <xsl:template match="/rng:grammar/c:class">
    <xsl:variable name="myName" select="@name" />
    <define name="{$myName}">
      <grammar>
        <xsl:apply-templates />
      </grammar>
    </define>
  </xsl:template>

  
  <xsl:template match="/rng:grammar/c:class/c:inherit">
    <xsl:variable name="myName" select="@name" />
    <xsl:variable name="myMom"  select=".." />
    
    <xsl:for-each select="/rng:grammar/c:class[@name =
$myName]/c:inherit">
      <xsl:apply-templates select="." />
    </xsl:for-each>
    
    <xsl:for-each select="/rng:grammar/c:class[@name =
$myName]/rng:define">
      <xsl:variable name="nameInContext" select="@name" />
      <xsl:if test="not($myMom/rng:define[@name=$nameInContext]) or
$myMom/rng:define[@name=$nameInContext][@combine]">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
      </xsl:if>
    </xsl:for-each>
    
    <xsl:for-each select="/rng:grammar/c:class[@name =
$myName]/rng:start">
      <xsl:if test="not($myMom/rng:start) or
$myMom/rng:start[@combine]">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
  

  <xsl:template match="node() | @*">
    <xsl:choose>
      <xsl:when test="(local-name(.)='inherit') and
(namespace-uri(.)=$rngwc)">
        <xsl:apply-templates select="@* | node()" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>




 

News | XML in Industry | Calendar | XML Registry
Marketplace | Resources | MyXML.org | Sponsors | Privacy Statement

Copyright 2001 XML.org. This site is hosted by OASIS