I have a file structure like this:
bookmap.ditamap
├── en-US/
│ └── CTR_MyProduct.ditamap
├── es-ES/
│ └── CTR_MyProduct.ditamap
└── fr-FR/
└── CTR_MyProduct.ditamap
The content of bookmap.ditamap is:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd">
<bookmap>
<booktitle><mainbooktitle/></booktitle>
<part>
<mapref href="en-US/CTR_Product.ditamap"/>
</part>
<part>
<mapref href="fr-FR/CTR_Product.ditamap"/>
</part>
</bookmap>
I'd like to have a Schematron rule which should crawl through the subdirectories looking for files starting with CTR_
and ending with .ditamap
which complains if there is no corresponding <part>
element, like:
<part>
<mapref href="xx-YY/CTR_Product.ditamap"/>
</part>
In this example, there is no <part>
element for the Spanish (es-ES
) map. This should be reported. Do you think this is possible to validate in Schematron?
With underlying XSLT/XPath 3 support and Saxon 9 or 10 or 11 you can probably do e.g.
every $uri in uri-collection('?select=CTR_Product.ditamap;recurse=yes')
satisfies
some $part in part
satisfies contains($uri, $part/mapref/@href)
If those elements are in a namespace you will need to set that up too as the default XPath selection namespace.
You can also use wildcards e.g. uri-collection('?select=CTR_*.ditamap;recurse=yes')
.
Perhaps using ends-with($uri, $part/mapref/@href)
instead of contains($uri, $part/mapref/@href)
is a better way to check.
More complete in the context of Schematron:
<sch:rule context="bookmap">
<sch:let name="parts" value="part"/>
<sch:let name="uris" value="uri-collection('?select=*.ditamap;recurse=yes')"/>
<sch:assert test="every $uri in $uris
satisfies
some $part in part
satisfies ends-with($uri, $part/mapref/@href)">
Not every URI exists.
<sch:value-of select="$uris[not(some $ref in $parts/mapref satisfies ends-with(., $ref/@href))]"/>
</sch:assert>
</sch:rule>