You 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. You will have to implement a Java extension class for obtaining the referred resources.
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 the
implementation you 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 the 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
the implementation you 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 the implementation is found in the Example Files Listings, the Java Files section.
In the listing below, the XML document contains the ref element:
<ref location="referred.xml">Reference</ref>
When no reference resolver is specified, the reference has the following layout:
When the above implementation is configured, the reference has the expected layout: