We need to provide a handler for resolving references and obtain the content they refer. In our case the element which has references is ref and the attribute indicating the referred resource is location. We will have to implement a Java extension class for obtaining the referred resources.
Create a new Java project, in your IDE.
Create the lib
directory in the Java
project directory and copy in it the oxygen.jar
file from the {oXygen_installation_directory}/lib
directory.
Create the class
simple.documentation.framework.ReferencesResolver
.
This class must implement the
ro.sync.ecss.extensions.api.AuthorReferenceResolver
interface.
import ro.sync.ecss.extensions.api.AuthorReferenceResolver; import ro.sync.ecss.extensions.api.AuthorAccess; import ro.sync.ecss.extensions.api.node.AttrValue; import ro.sync.ecss.extensions.api.node.AuthorElement; import ro.sync.ecss.extensions.api.node.AuthorNode; public class ReferencesResolver implements AuthorReferenceResolver {
The method hasReferences
verifies if
the handler considers the node to have references. It takes as
argument an AuthorNode
that represents
the node which will be verified. The method will return
true
if the node is considered to have
references. In our case, to be a reference the node must be an
element with the name ref and it must have
an attribute named location.
public boolean hasReferences(AuthorNode node) { boolean hasReferences = false; if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { AuthorElement element = (AuthorElement) node; if ("ref".equals(element.getLocalName())) { AttrValue attrValue = element.getAttribute("location"); hasReferences = attrValue != null; } } return hasReferences; }
The method getDisplayName
returns the
display name of the node that contains the expanded referred
content. It takes as argument an
AuthorNode
that represents the node
for which the display name is needed. The referred content
engine will ask this
AuthorReferenceResolver
implementation what is the display name for each node which is
considered a reference. In our case the display name is the
value of the location attribute from the
ref element.
public String getDisplayName(AuthorNode node) { String displayName = "ref-fragment"; if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { AuthorElement element = (AuthorElement) node; if ("ref".equals(element.getLocalName())) { AttrValue attrValue = element.getAttribute("location"); if (attrValue != null) { displayName = attrValue.getValue(); } } } return displayName; }
The method resolveReference
resolves
the reference of the node and returns a
SAXSource
with the parser and the
parser's input source. It takes as arguments an
AuthorNode
that represents the node
for which the reference needs resolving, the
systemID
of the node, the
AuthorAccess
with access methods to
the Author data model and a SAX
EntityResolver
which resolves
resources that are already opened in another editor or resolve
resources through the XML catalog. In our implementation we need
to resolve the reference relative to the
systemID
, and create a parser and an
input source over the resolved reference.
public SAXSource resolveReference( AuthorNode node, String systemID, AuthorAccess authorAccess, EntityResolver entityResolver) { SAXSource saxSource = null; if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { AuthorElement element = (AuthorElement) node; if ("ref".equals(element.getLocalName())) { AttrValue attrValue = element.getAttribute("location"); if (attrValue != null) { String attrStringVal = attrValue.getValue(); try { URL absoluteUrl = new URL(new URL(systemID), authorAccess.correctURL(attrStringVal)); InputSource inputSource = entityResolver.resolveEntity(null, absoluteUrl.toString()); if(inputSource == null) { inputSource = new InputSource(absoluteUrl.toString()); } XMLReader xmlReader = authorAccess.newNonValidatingXMLReader(); xmlReader.setEntityResolver(entityResolver); saxSource = new SAXSource(xmlReader, inputSource); } catch (MalformedURLException e) { logger.error(e, e); } catch (SAXException e) { logger.error(e, e); } catch (IOException e) { logger.error(e, e); } } } } return saxSource; }
The method getReferenceUniqueID
should
return an unique identifier for the node reference. The unique
identifier is used to avoid resolving the references
recursively. It takes as argument an
AuthorNode
that represents the node
with the reference. In our implementation the unique identifier
is the value of the location attribute from
the ref element.
public String getDisplayName(AuthorNode node) { String displayName = "ref-fragment"; if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { AuthorElement element = (AuthorElement) node; if ("ref".equals(element.getLocalName())) { AttrValue attrValue = element.getAttribute("location"); if (attrValue != null) { displayName = attrValue.getValue(); } } } return displayName; }
The method getReferenceSystemID
should
return the systemID
of the referred content.
It takes as arguments an AuthorNode
that
represents the node with the reference and the
AuthorAccess
with access methods to
the Author data model. In our implementation the we use the
value of the location attribute from the
ref element and resolve it relatively
to the XML base URL of the node.
public String getReferenceSystemID(AuthorNode node, AuthorAccess authorAccess) { String systemID = null; if (node.getType() == AuthorNode.NODE_TYPE_ELEMENT) { AuthorElement element = (AuthorElement) node; if ("ref".equals(element.getLocalName())) { AttrValue attrValue = element.getAttribute("location"); if (attrValue != null) { String attrStringVal = attrValue.getValue(); try { URL absoluteUrl = new URL(node.getXMLBaseURL(), authorAccess.correctURL(attrStringVal)); systemID = absoluteUrl.toString(); } catch (MalformedURLException e) { logger.error(e, e); } } } } return systemID; }
The complete source code of our implementation is found in the Example Files Listings, the Java Files section.
Package the compiled class into a jar file.
Copy the jar file into the frameworks/sdf
directory.
Add the jar file to the Author class path.
Register the Java class by clicking on the References resolver label. Press the button and select from the displayed
dialog the name of the class:
ReferencesResolver
.
In the listing below, the XML document contains the ref element:
<ref location="referred.xml">Reference</ref>
When reference resolver is specified, the reference has the following layout:
When the above implementation is configured, the reference has the expected layout: