As already presented in
Controlled Attribute Values for your DITA
Project, Oxygen allows you to add or replace possible values for attributes or
elements based on a simple configuration file. A more complex scenario is one in which in
order to decide which values to provide, you need more context information. Let's take this
DITA fragment:
<metadata>
<othermeta name="name" content="value"/>
</metadata>
What we want is to offer proposals for @content but the possible values for
@content depend on the value of @name. We will see how we can
solve this dependency.
Note: Starting with Oxygen 17.1 there is a simpler way to achieve the use case presented in this post. The
contextElementXPathExpression parameter will be bound to an XPath expression that identifies the element in the context of which the content completion was invoked.
The configuration file
The configuration file (
cc_value_config.xml) allows
calling an XSLT stylesheet and that's just what we
will
do:
<match elementName="othermeta" attributeName="content">
<xslt href="meta.xsl" useCache="false"/>
</match>
As you can see, we can't express the dependency between @content and
@name inside the configuration file . I also want to mention that because the
values for @content are dynamic, we want the XSLT script to execute every time
the values are requested (we shouldn't cache the results). We enforce this by setting
@useCache to false.
The XSLT script
The XSLT script has access to the XML document (through the
documentSystemID
parameter) but it lacks any context information, we can't really tell for which
othermeta element was the script invoked. To counter this limitation, we will
use Java extension functions and we will call Oxygen's Java-based API from the XSLT. Here
how it
looks:
<?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:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:tei="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:prov="java:ro.sync.exml.workspace.api.PluginWorkspaceProvider"
xmlns:work="java:ro.sync.exml.workspace.api.PluginWorkspace"
xmlns:editorAccess="java:ro.sync.exml.workspace.api.editor.WSEditor"
xmlns:saxon="http://saxon.sf.net/"
xmlns:textpage="java:ro.sync.exml.workspace.api.editor.page.text.xml.WSXMLTextEditorPage"
xmlns:authorPage="java:ro.sync.exml.workspace.api.editor.page.author.WSAuthorEditorPage"
xmlns:ctrl="java:ro.sync.ecss.extensions.api.AuthorDocumentController"
exclude-result-prefixes="xs xd"
version="2.0">
<xsl:param name="documentSystemID" as="xs:string"></xsl:param>
<xsl:template name="start">
<xsl:variable name="workspace" select="prov:getPluginWorkspace()"/>
<xsl:variable name="editorAccess" select="work:getEditorAccess($workspace, xs:anyURI($documentSystemID), 0)"/>
<xsl:variable name="pageID" as="xs:string" select="editorAccess:getCurrentPageID($editorAccess)"/>
<xsl:variable name="name" as="xs:string">
<xsl:choose>
<xsl:when test="$pageID='Text'">
<xsl:variable name="textpage" select="editorAccess:getCurrentPage($editorAccess)"/>
<xsl:value-of select="textpage:evaluateXPath($textpage, 'xs:string(./parent::node()/@name)')"/>
</xsl:when>
<xsl:when test="$pageID='Author'">
<xsl:variable name="authorPage" select="editorAccess:getCurrentPage($editorAccess)"/>
<xsl:variable name="caretOffset" select="authorPage:getCaretOffset($authorPage)"/>
<xsl:variable name="ctrl" select="authorPage:getDocumentController($authorPage)"/>
<xsl:variable name="contextNode" select="ctrl:getNodeAtOffset($ctrl, $caretOffset)"/>
<xsl:value-of select="ctrl:evaluateXPath($ctrl, 'xs:string(@name)', $contextNode, false(), false(), false(), false())[1]"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<items>
<xsl:choose>
<xsl:when test="$name = 'temperatureScale'">
<item value="Celsius" annotation="(symbol C)"/>
<item value="Fahrenheit" annotation="(symbol F)"/>
</xsl:when>
<xsl:when test="$name = 'measurement'">
<item value="Metric" annotation="Metric system"/>
<item value="Imperial" annotation="Also known as British Imperial"/>
</xsl:when>
</xsl:choose>
</items>
</xsl:template>
</xsl:stylesheet>