odd2odd.xsl sometimes fails to include some moduleSpec elements in the output
Say we have tiny.odd:
<schemaSpec ident="tiny" start="TEI" source="tei:current">
<moduleRef key="tei"/>
<moduleRef key="core"/>
</schemaSpec>
which we compile into a valid tiny_compiled.odd with odd2odd.xsl just fine.
If we now have tiny-prime.odd:
<schemaSpec ident="tiny-prime" start="TEI" source="tiny_compiled.odd">
<moduleRef key="tei"/>
<moduleRef key="core"/>
<moduleRef key="textstructure" source="tei:current"/>
</schemaSpec>
odd2odd.xsl will compile it into an invalid ODD, which fails to include a <moduleSpec> element for textstructure.
For memory, this is what the <moduleSpec> for textstructure looks like in p5subset.xml:
<moduleSpec xml:id="DDS" ident="textstructure">
<idno type="FPI">Default Text Structure</idno>
<desc xml:lang="en" versionDate="2006-09-13">Default text structure</desc>
...
</moduleSpec>
I understand the prime goal of odd2odd.xsl is not to produce valid ODDs, but it's rather nice when it does.
Also, I wonder if this has an impact on the resulting schema (e.g. RNG) when odd2odd.xsl is chained with another, schema-producing, XSLT.
I'm certain I have done this successfully in the past, e.g. putting back a module removed by the primary source schema by reaching back to the TEI schema. That ODD used a URL in the source pointing at the compiled ODD rather than the tei:current style URI. So possible that doesn't get correctly resolved if it's not on a schemaSpec element or that there's been a regression.
The tei:current pointer is correctly resolved (@hcayless), but somehow, the moduleRefs that have their own source are ignored.
The following fix works at least for the cases I need to cover. Insert the following block:
<xsl:for-each select="$top//tei:moduleRef[@source]">
<xsl:variable name="orig" select="tei:workOutSource(.)"/>
<xsl:variable name="key" select="normalize-space(@key)"/>
<xsl:variable name="themodspec"
select="document($orig)//tei:moduleSpec[normalize-space(@ident)=$key][1]"/>
<xsl:copy select="$themodspec">
<xsl:attribute name="n" select="ancestor::tei:div[last()]/@xml:id"/>
<xsl:copy-of select="@*"/>
</xsl:copy>
</xsl:for-each>
just after https://github.com/TEIC/Stylesheets/blob/3a12490d9873ee9df7bf5c400a24417fc774848a/odds/odd2odd.xsl#L2234 Maybe someone could refine this into a permanent fix?
But @YvesMarcoux , that code copies the <moduleSpec> element itself, no? A <moduleRef> is supposed to refer to those specification elements that declare themselves to be “in” the given module. I.e., something more along the lines of <xsl:copy-of select="document($orig)//*[@module eq $key]"/>.
Yes, it does copy the <moduleSpec> itself, and that's the point. At the moment, the resulting ODD (let's call it tiny-prime_compiled.odd) has multiple @module="textstructure" attributes in it (one for each of the things in that module), but it fails to have a <moduleSpec> for that module. Hence, the schematron errors (33 of them) we get on tiny-prime_compiled.odd.
In contrast, tiny-prime_compiled.odd does have a <moduleSpec> for each of the two other modules included by way of a <moduleRef> that does not have a @source attribute (the higher-level @source of the <schemaSpec> being used in these cases).
I think the schematron errors make sense, because a compiled ODD should be self-sufficient, right? So it should have in itself a <moduleSpec> for each module it includes, no?
Anyway, my fix works fine (i.e., it results in an ODD that is valid [in particular, no schematron error] and corresponds to what we want) for the cases I need to handle at the moment. I am not suggesting it as a "true" fix because, not being an ODD specialist, I am worried it might not work properly in all possible cases.
@sydb To add a bit more detail, here are the (pretty-printed) last lines of tiny-prime_compiled.odd without my fix:
...
</elementSpec>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:teix="http://www.tei-c.org/ns/Examples"
xmlns:xi="http://www.w3.org/2001/XInclude" n="ST" xml:id="DSTTEI2" ident="tei"
type="core"/>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:teix="http://www.tei-c.org/ns/Examples"
xmlns:xi="http://www.w3.org/2001/XInclude" n="CMC" ident="cmc"/>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:teix="http://www.tei-c.org/ns/Examples" n="CO" xml:id="DCO" ident="core"/>
</schemaSpec>
</body>
</text>
</TEI>
We see it has a moduleSpec for each of tei, cmc (I don't really know why), and core.
With my fix, a fourth moduleSpec is added, for textstructure:
...
</elementSpec>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:teix="http://www.tei-c.org/ns/Examples"
xmlns:xi="http://www.w3.org/2001/XInclude" n="ST" xml:id="DSTTEI2" ident="tei"
type="core"/>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:teix="http://www.tei-c.org/ns/Examples"
xmlns:xi="http://www.w3.org/2001/XInclude" n="CMC" ident="cmc"/>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
xmlns:teix="http://www.tei-c.org/ns/Examples" n="CO" xml:id="DCO" ident="core"/>
<moduleSpec xmlns:rng="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron" n="DS" xml:id="DDS"
ident="textstructure"/>
</schemaSpec>
</body>
</text>
</TEI>
That's the only difference the fix makes. But it makes the ODD valid.