Package org.apache.sis.xml
Class Transformer
java.lang.Object
org.apache.sis.xml.Transformer
- Direct Known Subclasses:
TransformingReader
,TransformingWriter
Base class of XML reader or writer replacing the namespaces used in JAXB annotations by namespaces used in
the XML document, or conversely (depending on the direction of the I/O operation). The Why using
When the XML schemas of an international standard is updated, the URL of the namespace is often modified.
For example, when GML has been updated from version 3.1 to 3.2, the URL mandated by the international standard
changed from
Transform*
classes in this package perform a work similar to XSLT transformers, but using a lighter implementation at
the expense of less transformation capabilities. This transformer supports:
- Renaming namespaces, which may depend on the parent element.
- Renaming elements (classes or properties).
- Moving elements provided that the old and new locations are in the same parent element.
Transformer
is not expected to transform fully a XML document by itself. It is rather designed to complete JAXB: some
transformations are better handled with Java methods annotated with JAXB (see for example the deprecated
methods in org.apache.sis.metadata.iso
packages for legacy ISO 19115:2003 properties), and some
transformations, in particular namespace changes, are better handled by this Transformer
.
Why using Transformer
When the XML schemas of an international standard is updated, the URL of the namespace is often modified.
For example, when GML has been updated from version 3.1 to 3.2, the URL mandated by the international standard
changed from "http://www.opengis.net/gml"
to "http://www.opengis.net/gml/3.2"
(XML namespaces usually have a version number or publication year - GML before 3.2 were an exception).
The problem is that namespaces in JAXB annotations are static. The straightforward solution is
to generate complete new set of classes for every GML version using the xjc
compiler.
But this approach has many inconvenient:
- Massive code duplication (hundreds of classes, many of them strictly identical except for the namespace).
- Handling of above-cited classes duplication requires either a bunch of
if (x instanceof Y)
in every SIS corners, or to modify thexjc
output in order to give to generated classes a common parent class or interface. In the latter case, the auto-generated classes require significant work anyways. - The namespaces of all versions appear in the
xmlns
attributes of the root element (we cannot always create separated JAXB contexts), which is confusing and prevent usage of usual prefixes for all versions except one.
XMLEventReader
and XMLEventWriter
as "micro-transformers". One advantage is that they can transform on-the-fly (no need to load and transform the
document in memory). It also avoid the need to detect in advance which schemas a XML document is using, and can
handle the cases where mixed versions are used.- Since:
- 1.0
- Version:
- 1.0
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final char
Character used for separating a class name from the parent class name.The namespaces associated to prefixes in the source.(package private) static final char
A flag after type name in files loaded byload(boolean, String, Set, int)
, meaning that the type itself is in a different namespace than the properties listed below the type.Properties of the last outer elements, ornull
if not yet determined.List of encountered XML tags, used for backtracking.private static final char
Character used for separating an old name from the new name.Temporary list of attributes after their namespace change.private static final char
Heading character for declaring a namespaces on which the remaining of theRename.lst
file applies.(package private) final TransformVersion
The external XML format version to (un)marshal from. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionReturns a snapshot ofrenamedAttributes
list and clears the latter.void
close()
Frees any resources associated with this reader.(package private) final void
Notifies that we are closing an element of the given name.(package private) final QName
Renames en element using the namespaces map given to theopen(…)
andclose(…)
methods.(package private) final Attribute
Imports or exports an attribute read or written from/to the XML document.(package private) static boolean
isNamespace
(String candidate) Returnstrue
if the given string is a namespace URI, orfalse
if it is a property name.private static boolean
isTypeElement
(String localPart) Returnstrue
if an element with the given name is an OGC/ISO type (as opposed to property).Loads a file listing types and properties contained in namespaces.(package private) final void
Notifies that a new namespace is declared in the source.(package private) final void
Notifies that we are opening an element of the given name.(package private) abstract String
prefixReplacement
(String previous, String namespace) Returns the prefix to use for a name in a new namespace.(package private) abstract String
Returns the new namespace for elements (types and properties) in the given namespace.(package private) static String
Removes the trailing slash in given URI, if any.renamingMap
(String namespace) Returns the map loaded byload(boolean, String, Set, int)
.
-
Field Details
-
TARGET_PREFIX
private static final char TARGET_PREFIXHeading character for declaring a namespaces on which the remaining of theRename.lst
file applies. Lines with this prefix specify legacy namespaces to be renamed (the target of the renaming process), while lines without this prefix specify new namespaces.- See Also:
-
RENAME_SEPARATOR
private static final char RENAME_SEPARATORCharacter used for separating an old name from the new name. For example, inSV_OperationMetadata
,"DCP"
in ISO 19139:2007 has been renamed"distributedComputingPlatform"
in ISO 19115-3. This is encoded in "RenameOnImport.lst" file as"DCP/distributedComputingPlatform"
.- See Also:
-
EXTENDS
private static final char EXTENDSCharacter used for separating a class name from the parent class name. When theChild : Parent
syntax is used, the child inherits all properties defined in the parent. The parent class must be defined before the child class (no forward reference). We do not store the relationship between the two classes, so it is not necessary to extend a parent that define no property.- See Also:
-
NO_NAMESPACE
static final char NO_NAMESPACEA flag after type name in files loaded byload(boolean, String, Set, int)
, meaning that the type itself is in a different namespace than the properties listed below the type. For example in the following:SV_ServiceIdentification
type is defined in the"http://standards.iso.org/iso/19115/-3/srv/2.0"
namespace, but thecitation
andabstract
properties inherited fromIdentification
are defined in thehttp://standards.iso.org/iso/19115/-3/mri/1.0
namespace (note: usingEXTENDS
is a better way to achieve the same result for this particular example). If the '!' flag is not present, then the type is assumed in the same namespace than the properties (this is the most common case).- See Also:
-
version
The external XML format version to (un)marshal from. -
outerElements
List of encountered XML tags, used for backtracking. Elements are removed from this list when they are closed. Names should be the ones we get after conversion from namespaces used in XML document to namespaces used in JAXB annotations. For example, given the following XML, this list should containcit:CI_Citation
,cit:date
andcit:CI_Date
(in that order) when the (un)marshalling reaches the "…" location. -
outerElementProperties
Properties of the last outer elements, ornull
if not yet determined. If non-empty, this is one of the values got from the map given in argument toopen(QName)
. -
renamedAttributes
Temporary list of attributes after their namespace change. This list is recycled for each XML element to be read or written. -
namespaces
The namespaces associated to prefixes in the source. When unmarshalling, this is for the namespaces in the source XML document (e.g. using legacy ISO 19139:2007 standard). When marshalling, this is for the namespaces in the JAXB annotations (e.g. using newer ISO 19115-3 standard). This is used for handlingxsi:type
attribute values.
-
-
Constructor Details
-
Transformer
Transformer(TransformVersion version) Creates a new XML reader or writer.
-
-
Method Details
-
removeTrailingSlash
Removes the trailing slash in given URI, if any. It is caller's responsibility to ensure that the URI is not null and not empty before to invoke this method. -
isNamespace
Returnstrue
if the given string is a namespace URI, orfalse
if it is a property name. This method implements a very fast check based on the presence of':'
in"http://foo.bar"
. It assumes that all namespaces declared in files loaded byload(boolean, String, Set, int)
use the"http"
protocol and no property name use the':'
character. -
load
static Map<String,Map<String, loadString>> (boolean export, String filename, Set<String> targets, int capacity) Loads a file listing types and properties contained in namespaces. The file location is relative to theTransformer
class. The file format is a tree structured with indentation as below:- Lines with zero-space indentation are namespace URIs.
- Lines with one-space indentation are classes within the last namespace URIs found so far.
- Lines with two-spaces indentation are properties within the last class found so far.
- All other indentations are illegal and cause an
InvalidPropertiesFormatException
to be thrown. This exception type is not really appropriate since the file format is not a.properties
file, but it is the closest we could find in existing exceptions and we don't want to define a new exception type since this error should never happen.
- Keys are XML names of types, ignoring
"_TYPE"
suffix (e.g."CI_Citation"
) - Values are maps where:
- Keys are XML names of properties (e.g.
"title"
) - Values are either:
- Namespace URI if
isNamespace(String)
returnstrue
for that value. - New name of the element otherwise. In such case, the map must be queried again with that new name for obtaining the namespace.
- Namespace URI if
- Keys are XML names of properties (e.g.
- Parameters:
export
-true
for"RenameOnImport.lst"
,false
for"RenameOnImport.lst"
.filename
- name of the file to load. Shall be consistent with theexport
flag.targets
- initially empty set where to add the namespaces on which the renaming will apply.capacity
- initial capacity for the hash map to be returned. This is only a hint.
-
notify
Notifies that a new namespace is declared in the source. When unmarshalling, this is for a namespace in the source XML document (e.g. using legacy ISO 19139:2007 standard). When marshalling, this is for a namespaces in the JAXB annotations (e.g. using newer ISO 19115-3 standard). -
attributes
Returns a snapshot ofrenamedAttributes
list and clears the latter. -
convert
Imports or exports an attribute read or written from/to the XML document. If there is no name change, then this method returns the given instance as-is. This method performs a special check for the"xsi:type"
attribute: its value is parsed as a name and converted.- Throws:
XMLStreamException
-
isTypeElement
Returnstrue
if an element with the given name is an OGC/ISO type (as opposed to property). For example, given the following XML, this method returnstrue
forcit:CI_Date
butfalse
forcit:date
: This method is based on simple heuristic applicable to OGC/ISO conventions, and may change in any future SIS version depending on new formats to support.Other examples to keep in mind:
"AbstractCI_Party"
(a type)."ISBN"
and"ISSN"
(properties)."MI_GCP"
(a type).
-
open
Notifies that we are opening an element of the given name.- Parameters:
name
- element name as declared in JAXB annotations.
-
close
Notifies that we are closing an element of the given name. This method closes the last start element with a matching name. It should be the last element on the list in a well-formed XML, but we loop in the list anyway as a safety.- Parameters:
name
- element name as declared in JAXB annotations.
-
close
Frees any resources associated with this reader.- Throws:
XMLStreamException
-
convert
Renames en element using the namespaces map given to theopen(…)
andclose(…)
methods. When unmarshalling, this method converts a name read from the XML document to the name to give to JAXB. When marshalling, this method converts a name used in JAXB annotation to the name to use in XML document. The new namespace depends on both the old namespace and the element name. The prefix is computed byprefixReplacement(String, String)
.- Parameters:
name
- the name of the element or attribute currently being read or written.- Returns:
- a name with potentially the namespace and the local part replaced.
- Throws:
XMLStreamException
-
renamingMap
Returns the map loaded byload(boolean, String, Set, int)
. This is a static field in theTransformingReader
orTransformingWriter
subclass.- Parameters:
namespace
- the namespace URI for which to get the substitution map (never null).- Returns:
- the substitution map for the given namespace, or an empty map if none.
-
relocate
Returns the new namespace for elements (types and properties) in the given namespace. This method is used only for default relocations, i.e. the fallback to apply when no explicit rule has been found. -
prefixReplacement
Returns the prefix to use for a name in a new namespace.- Parameters:
previous
- the prefix associated to old namespace.namespace
- the new namespace URI.- Returns:
- prefix to use for the new namespace.
- Throws:
XMLStreamException
- if an error occurred while fetching the prefix.
-