Resolving DITA Cross-References in Refactoring Operations
We needed a way to resolve DITA <xref> and <link>
            elements to their target element in a refactoring operation. We also needed to determine
            whether the link was a local or peer-map reference. Fortunately, Oxygen v25.1 provided
            us with the solution!
The Missing Piece - Resolving a @keyref
For <xref> and <link> elements, we use a mix
                of @href and @keyref references in our content. In
                XSLT refactoring operations, we could resolve @href references to
                the target file (and optionally, an element in that file) by using the XPath
                    document() function. However, we had no way of resolving
                    @keyref references because a refactoring operation only
                processes the current file (it doesn't consider Oxygen's map context or the keys
                defined within it). In addition, writing such a resolver in XSLT that properly
                considers keyscopes would be enormously difficult.
In the Oxygen v25.1 release, new API functions were introduced to provide
            information about @keyref references:
- 
                The getKeyRefInfo()function returns information about a reference's type (local, peer, unresolved, and so on).
- 
                The getKeyRefAbsoluteReference()function resolves a@keyrefto its equivalent@hrefreference URL.
There were subsequent improvements to the API functions in Oxygen v25.1 build 2023070306, so you should use that release or later for best results.
Thanks to this new API, we could use a simple @href resolver written in
            XSLT for @keyref references too!
Resolving Cross-References in Refactoring Operations
The attached test case provides the following XSLT file that you can include in your own refactoring operations:
frameworks/dita/refactoring/util-get-referenced-element.xsl
This file defines a mode="get-referenced-element" template that,
                when applied to any element with an @href or
                    @keyref attribute, returns the referenced element. If the
                reference cannot be resolved, the template returns an empty sequence.
The template works as follows:
- 
                    References with @scope="external"
- 
                    References with @formatset to a value other than"dita"always return an empty sequence.
- 
                    If the reference has a @keyref, it is converted to an@hrefvalue usinggetKeyRefAbsoluteReference().
- 
                    The @hrefvalue is parsed into its components as follows:[file]#topic_id[/element_id]
- 
                    The target document is obtained as follows: - 
                            If no file is specified, the in-memory document that contains the cross-reference element is used. 
- 
                            If a file is specified and that file contains the cross-reference element, the in-memory document that contains the cross-reference element is used. 
- 
                            Otherwise, the specified file document is loaded from disk using the XPath document()function.
 This heuristic approach ensures that in multiple-pass refactoring operations, the in-memory version of the content is preferred over the on-disk version. 
- 
                            
- 
                    The topic that matches the topic_id value is obtained from the target document. 
- 
                    If an element_id is specified, the element in the topic that matches the element_id value is obtained. Because non-topic @idvalues do not need to be unique, the code ensures that no subtopics within the matching topic are searched to avoid incorrect matches.
To view the XSLT stylesheet without downloading the archive, click on the following link:
util-get-referenced-element.xsl
There are comments in the code to explain how it works.
The @keyref API functions require that a map context be active in
                Oxygen. If no context is available (for example, no map is open in the
                    DITA Maps Manager), there will be no key information
                available to resolve the reference.
Example Test Case
The following Oxygen project provides examples of how cross-reference resolutions can be used in refactoring operations and Schematron checks:
resolving_refs_refactoring.zip
Specifically, it provides the following:
- 
                    An "Update Cross References" refactoring operation is provided that: - 
                            Sets (or updates) the @typeattribute for<xref>and<link>elements. 
 
- 
                            Populates the target text for <xref>and<link>elements that reference topics in peer maps (i.e. cross-book links). 
 
 
- 
                            
- 
                    Schematron checks are provided that: - 
                            Warn about <xref>and<link>elements that reference topics in peer maps (i.e. cross-book links) but do not contain any target text. 
 This check also offers a "quick fix" that populates the target text for you. 
- 
                            Show the value of the getKeyRefInfo()andgetKeyRefAbsoluteReference()API calls for any element with a@keyrefattribute. 
 These informational checks are commented out by default. You can uncomment them in the following file: frameworks/dita/sch/checks.sch 
 
- 
                            
When target text is added to a peer map (cross-book) reference, an
                    <?oxy-peertext?> processing instruction is added to
                indicate that the text was updated automatically. If you remove this processing
                instruction and customize the target text, your customized text will not be
                disturbed by future automatic updates.
