I have created a custom plugin in DITA-OT 3.4 named com.myorg.dita.html5, which is an extension of the base plugin org.dita.html5. The plugin is set up correctly and functioning as expected.
In the main custom XSLT file of this plugin, I process each topic by matching the root node using <xsl:template match="/">. There are other XSLTs in plugin to apply relavant customizations.
My Current challenge is; I need to find all the elements that has class=topic/xref
that has <data>
element as child or descendant and does not have any value in @value attribute. I need to record all such instances during the entire dita-ot process. If any error recorded then print it and terminate the dita-ot process. I need to do this in this XSL if possible.
My Original xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output method="html" encoding="utf-8" indent="no"/>
<!-- root rule -->
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
What I'm trying:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="xs exsl" version="2.0">
<xsl:output method="html" encoding="utf-8" indent="no"/>
<xsl:variable name="errorLog" as="element()*"/>
<!-- root rule -->
<xsl:template match="/">
<xsl:apply-templates/>
<xsl:apply-templates select="//*[contains(@class, ' topic/xref ')]" mode="test"/>
<xsl:if test="$errorLog">
<!-- Print the errors -->
<xsl:message terminate="Yes">
<xsl:text>List of all the errors </xsl:text>
<xsl:copy-of select="$errorLog"/>
</xsl:message>
</xsl:if>
</xsl:template>
<xsl:template match="*[contains(@class, 'topic/xref')]" mode="test">
<xsl:if test="exists(//data) and not(//data/@value ='')">
<!-- Append the error to the errorLog variable -->
<xsl:copy-of select="."/>
<xsl:sequence select="$errorLog, current()"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
How to achieve this?
This sounds as if an XSLT 3.0 accumulator could help. XSLT 2 and DITA-OT are usually run with Saxon, the currently supported versions of Saxon are 10, 11, 12, which are all XSLT 3.0 processors anyway and just support XSLT 2 stylesheets through backwards compatibility.
So you could try e.g.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="xs exsl" version="3.0">
<xsl:output method="html" encoding="utf-8" indent="no"/>
<xsl:accumulator name="errorLog" as="element()*" initial-value="()">
<xsl:accumulator-rule match="*[contains(@class, 'topic/xref')][exists(//data) and not(//data/@value ='')]" select="$value, ."/>
</xsl:accumulator>
<!-- root rule -->
<xsl:template match="/">
<xsl:apply-templates/>
<xsl:apply-templates select="//*[contains(@class, ' topic/xref ')]" mode="test"/>
<xsl:if test="accumulator-after('errorLog')">
<!-- Print the errors -->
<xsl:message terminate="Yes">
<xsl:text>List of all the errors </xsl:text>
<xsl:copy-of select="accumulator-after('errorLog')"/>
</xsl:message>
</xsl:if>
</xsl:template>
<xsl:mode name="test" on-no-match="shallow-skip" use-accumulators="errorLog"/>
<xsl:mode use-accumulators="errorLog"/>
</xsl:stylesheet>
Note that I have used the conditions from your original code in the accumulator rule with e.g.
<xsl:accumulator name="errorLog" as="element()*" initial-value="()">
<xsl:accumulator-rule match="*[contains(@class, 'topic/xref')][exists(//data) and not(//data/@value ='')]" select="$value, ."/>
</xsl:accumulator>
but I suspect you rather want
<xsl:accumulator name="errorLog" as="element()*" initial-value="()">
<xsl:accumulator-rule match="*[contains(@class, 'topic/xref')][exists(.//data) and not(.//data/@value ='')]" select="$value, ."/>
</xsl:accumulator>