Question

I'm trying to generate very simple documentation from the annotations in a Relax NG XML Schema. For example, given the following Relax NG:

<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
    <start>
        <element name="topNode">
            <ref name="topNode-ref"/>
        </element>
    </start>

    <define name="topNode-ref">
        <a:documentation>This is the top of the doc.</a:documentation>
        <oneOrMore>
            <element name="level1">
                <ref name="level1-ref"/>
            </element>
        </oneOrMore>
    </define>

    <define name="level1-ref">
        <a:documentation>Here's some notes about level1.</a:documentation>
        <attribute name="att1">
            <a:documentation>Details about att1.</a:documentation>
        </attribute>
        <element name="subLevel2">
            <ref name="subLevel2-ref"/>
        </element>
    </define>

    <define name="subLevel2-ref">
        <a:documentation>Notes on subLevel2.</a:documentation>
        <attribute name="subAtt"/>
        <zeroOrMore>
            <element name="subLevel3">
                <ref name="subLevel3-ref"/>
            </element>
        </zeroOrMore>
    </define>

    <define name="subLevel3-ref">
        <a:documentation>And here is subLevel3.</a:documentation>
        <attribute name="subSubAtt"/>
    </define>
</grammar>

Which would be used to valid an XML file like:

<?xml version="1.0" encoding="UTF-8"?>
<topNode>
    <level1 att1="some test">
        <subLevel2 subAtt="more text"></subLevel2>
    </level1>

    <level1 att1="quick">
        <subLevel2 subAtt="brown">
            <subLevel3 subSubAtt="fox"></subLevel3>
        </subLevel2>
    </level1>   
</topNode>

I'd like to be able to produce documentation that lists the basic XPath to each element/attribute and then display any corresponding documentation annotations. For example:

/topNode
This is the top of the doc.

/topNode/level1
Here's some notes about level1

/topNode/level1/@att1
Details about att1.

etc...

Eventually, I'll add in more documentation about "zeroOrMore", possible data types, etc... but I need to get this first step solved first.

I've found the Techquila RELAX-NG Documentation Tools. I've played around with the rng to docbook stylesheet, but it don't do what I'm looking for. It just lists elements individually with no details about the XPath as far as I can tell. I don't see how I can use it as a starting point to get the output I'm after.

Is it possible (and if so, how?) to produce this type of documentation output with XSLT given the RelaxNG example provided?

While XSLT would be ideal, it's not a requirement. I'm open for anything that gets the job done.

Was it helpful?

Solution

This will work for a very simple grammar like your example.

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:r="http://relaxng.org/ns/structure/1.0" 
    xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"
>
<xsl:output method="text" />

<xsl:template match="/">
    <xsl:apply-templates select="//r:define[a:documentation] | //r:attribute[a:documentation]" />
</xsl:template>

<xsl:template match="r:define">
    <xsl:variable name="doc" select="a:documentation" />
    <xsl:call-template name="print-path">
        <xsl:with-param name="elm" select="//r:element[r:ref/@name=current()/@name]" />
    </xsl:call-template>
    <xsl:value-of select="$doc" /><xsl:text>&#10;</xsl:text>
</xsl:template>

<xsl:template match="r:attribute">
    <xsl:variable name="doc" select="a:documentation" />
    <xsl:call-template name="print-path">
        <xsl:with-param name="elm" select="//r:element[r:ref/@name=current()/ancestor::r:define/@name]" />
        <xsl:with-param name="path" select="concat('/@',@name)" />
    </xsl:call-template>
    <xsl:value-of select="$doc" /><xsl:text>&#10;</xsl:text>
</xsl:template>

<xsl:template name="print-path">
    <xsl:param name="elm" />
    <xsl:param name="path" />

    <xsl:variable name="parent" select="//r:ref[@name=$elm/ancestor::r:define/@name]/ancestor::r:element" />
    <xsl:message><xsl:value-of select="$elm/@name" /></xsl:message>
    <xsl:choose>
        <xsl:when test="$parent">
            <xsl:call-template name="print-path">
                <xsl:with-param name="elm" select="$parent" />
                <xsl:with-param name="path" select="concat('/',$elm/@name,$path)" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="concat('/',$elm/@name,$path)" /><xsl:text>&#10;</xsl:text>            
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top