Preserving Entity References
This section describes the concepts behind preserving entity references. For the resources associated with this sample, see this section in Bitbucket.
XML documents sometimes contain entity references. While entity references can be either expanded or left as references within an XML document, they are not by default processed during a comparison. This is of course not always an issue but sometimes it is necessary to include entity references in the result. To achieve this, they need to be converted into XML elements within the document and then converted back again after comparison. This sample explains how this can be achieved using filters provided in the DeltaXML product.
Note that it may be easier to select one of the pre-configured lexical preservation modes as discussed in the Guide to Lexical Preservation, as some of them include entity preservation (e.g. the roundTrip preservation mode).
Simple API Approach
A simple approach for retaining entity references is to enable the built-in lexical preservation on our comparators, such as the PipelinedComparator, which are configured by passing them a LexicalPreservationConfig object. The following code extract illustrates how to enable just entity references preservation on a LexicalPreservationConfig object.
LexicalPreservationConfig lpc = new LexicalPreservationConfig("base");
lpc.setPreserveEntityReplacementText(false);
lpc.setPreserveEntityReferences(true);
Having enabled the preservation the next step is to specify how changes in entity references should be handled. In some cases, such as when there is no way of representing a change in an entity reference, it may be appropriate to output the newer 'B' version:
lpc.setAdvancedEntityReferenceUsage(AdvancedEntityRefUsage.SPLIT);
It is also possible to detect changes in the content of an entity reference, by retaining both the entity reference and its replacement text, before the comparison is performed. Following the comparison, any changes in the replacement text will be identified using the usual scheme.
LexicalPreservationConfig lpc = new LexicalPreservationConfig("base");
lpc.setPreserveEntityReferences(true);
lpc.setPreserveNestedEntityReferences(true);
Note that if both the entity reference and replacement text are being preserved then it is possible to choose which should be retained in the output using the lpc.setUseEntityReferences method. The default behaviour is to preserve the entity references, rather than use the associated replacement text.
For further information on the representation of the entity declarations and references please refer to the Explanation section of this sample.
Running the Sample
For the resources associated with this sample, see here. The resources must be checked out, cloned or downloaded and unzipped into the samples directory of the release. They should be located such that they are two levels below the top level release directory, for example DeltaNova-year.x.y.z_j/samples/preserving-doctype-information.
Explanation
The following explanation makes use of a simplified variant of the sample input files. The key changes are that the DOCTYPE has been changed from XHTML to one specified solely by an internal subset, and that the explanatory text has been removed.
Converting Entity References into XML
The first step in preserving entity references is to convert them into XML elements.
Example 1: an XML file containing entity references
<!DOCTYPE root [
<!ELEMENT root (p*)>
<!ELEMENT p (#PCDATA)>
<!ENTITY city1 "Bath">
<!ENTITY city2 "York">
<!ENTITY city3 "Bath">
<!ENTITY p1 "<p>From &city1; to &city2;.</p>">
<!ENTITY p2 "<p>From &city1; to &city3;.</p>">
]>
<root>
<p>City 1 is &city1;</p>
<p>City 2 is &city2;</p>
&p1; &p2;
</root>
Example 2: the XML file after passing through the lexical preservation input processing
Part 1 — Encoding the doctype and internal subset declarations:
<root xmlns:preserve="http://www.deltaxml.com/ns/preserve"
xmlns:er="http://www.deltaxml.com/ns/entity-references"
xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1">
<preserve:doctype name="root">
<preserve:elementDecl name="root" deltaxml:key="element_root" model="(p*)" />
<preserve:elementDecl name="p" deltaxml:key="element_p" model="(#PCDATA)" />
<preserve:internalParsedGeneralEntityDecl name="city1" value="Bath"
deltaxml:key="entity_gen_city1" />
<preserve:internalParsedGeneralEntityDecl name="city2" value="York"
deltaxml:key="entity_gen_city2" />
<preserve:internalParsedGeneralEntityDecl name="city3" value="Bath"
deltaxml:key="entity_gen_city3" />
<preserve:internalParsedGeneralEntityDecl name="p1"
value="!(*lt!)p!(*gt!)From !(*amp!)city1; to !(*amp!)city2;./!(*lt!)p!(*gt!)"
deltaxml:key="entity_gen_p1" />
<preserve:internalParsedGeneralEntityDecl name="p2"
value="!(*lt!)p!(*gt!)From !(*amp!)city1; to !(*amp!)city3;./!(*lt!)p!(*gt!)"
deltaxml:key="entity_gen_p2" />
</preserve:doctype>
Note that the encoded value of the p1 and p2 entity declarations makes use of a non-standard XML entity character encoding scheme, as this simplifies some of the lexical preservation processing.
Part 2a — Encoding the body in the preconfigured roundTrip preservation mode:
<er:city1/>
<er:city2/>
<er:p1/>
</root>
Part 2b — Encoding the body in the preconfigured entityRef preservation mode:
<er:city1>Bath</er:city1>
<er:city2>York</er:city2>
<er:p1><p>From Bath to York.</p></er:p1>
<er:p2><p>From Bath to Bath.</p></er:p2>
</root>
Part 2c — Encoding the body in the preconfigured nestedEntityRef preservation mode:
<er:city1>Bath</er:city1>
<er:city2>York</er:city2>
<er:p1><p>From <er:city1>Bath</er:city1> to <er:city2>York</er:city2>.</p></er:p1>
<er:p2><p>From <er:city1>Bath</er:city1> to <er:city3>Bath</er:city3>.</p></er:p2>
</root>