[
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>
|