12013 design
Part of Plans for DITA Open Toolkit 1.5
Design for implementing "conref range" in the DITA Open Toolkit
What user need will be met by this feature?
Users can use @conref combined with @conrefend to refer to a range of sibling elements and pull them into the specified location.
What is the technical design for the change
In conrefImpl.xsl, when the target of @conref is processed, the code first copy or proceed all @* attributes of target elements and then use apply-templates on its sub-nodes. After that we need to add the code to check whether @conrefend is valid and proceed the elements in the conref range. Since the template to proceed conref target doesn't know whether there is @conrefend at conref source, the value of @conrefend should be passed as parameter.
Another piece of code we need to change is "<xsl:copy>". In current code, <xsl:copy> is used in <xsl:template match="*[@conref][@conref!='']" priority="10">. The code proceed the conref source element and keep necessary @* attributes before go to conref target. But if we want to proceed range conref, the generated sibling elements will be sibling to the conref source element and logic of <xsl:copy> should be moved to the code which proceed conref target. Thus <xsl:copy> in <xsl:template match="*[@conref][@conref!='']" priority="10"> need to be removed and the info of conref source element needs to be transmitted as a parameter to the template which proceeds conref target elements.
Here is the current template to proceed conref-target in conrefImpl.xsl with update comments in bold
<xsl:template match="*" mode="conref-target">
************************************************
We need to add a parameter here to accept the value of @conrefend. The default value is #none# which means that there is no @conrefend
************************************************
************************************************
We need to add a parameter to accept the info of conref source element and generate the element in this template.
************************************************
<xsl:param name="WORKDIR"/>
<xsl:param name="conref-source-topicid"/>
<xsl:param name="conref-ids"/>
<xsl:param name="source-element"/>
<xsl:param name="current-relative-path"/> <!-- File system path from original file to here -->
<xsl:param name="conref-filename"/>
.......calculate topic id and element id..........
<!-- If for some bizarre reason you conref to another element that uses @conref, forget the original and continue here. -->
<xsl:choose>
<xsl:when test="@conref">
.......proceed @conref of the conref target.........
</xsl:when>
<xsl:otherwise>
***********************************************
Generate the conref source element and its attributes
***********************************************
<xsl:for-each select="@*">
.......proceed every @* attribute.........
</xsl:for-each>
<!-- Continue processing this element as any other -->
<xsl:apply-templates select="*|comment()|processing-instruction()|text()">
......apply templates on sub-nodes.......
</xsl:apply-templates>
***********************************************
End of generating the conref source element
***********************************************
</xsl:otherwise>
</xsl:choose>
***************************************************************
Here we need to add the logic to proceed @conrefend if the value of @conrefend is sent to this template as variable.
***************************************************************
</xsl:template>
How to address the elements in the conref range?
If @conrefend is valid, there must be a following sibling to the conref target which has the same id as @conrefend specified. If @conrefend is not valid, we would ignore @conrefend and report a warning message saying that @conrefend is not valid. If valid, we should use following XPath expression to address all of the elements between conref start and conref end.
following-sibling::*[following-sibling::*[@id=$conrefend-elem-id]]
This XPath expression is used to address all of the following siblings to current conref target with condition that @conrefend element is also their following sibling.
We created a sample demo to prove that this XPath can be accepted by XSLT processor. Here is the demo.
***********1.xml************
<?xml version="1.0" encoding="UTF-8"?>
<stub>
<li id="a"></li>
<li id="b"></li>
<li id="c"></li>
<li id="d"></li>
<li id="e"></li>
<li id="f"></li>
<li id="g"></li>
<li id="h"></li>
<li id="i"></li>
<li id="k"></li>
</stub>
********2.xsl***********
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:for-each select="/stub/*[preceding-sibling::*[@id='a']][following-sibling::*[@id='g']]">
<xsl:copy>
<xsl:copy-of select="@*|*|text()|comment()|processing-instruction()"/>
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
In this demo, 2.xsl get all elements between a and g and copy them to the output.
What sections of the toolkit will be impacted by the change?
The change will impact conref resolution xslt script.
See also
none