Author: desruisseaux
Date: Sun Apr 15 17:51:32 2018
New Revision: 1829214
URL: http://svn.apache.org/viewvc?rev=1829214&view=rev
Log:
Replace the namespace in "xsi:type" attribute value and automatically add a
local "xmlns:lan" attribute if needed.
https://issues.apache.org/jira/browse/SIS-399
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformedEvent.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/FreeTextMarshallingTest.java
sis/branches/JDK8/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/PositionalAccuracy.xml
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformedEvent.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformedEvent.java?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformedEvent.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformedEvent.java
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -61,8 +61,8 @@ abstract class TransformedEvent<E extend
* @param name the exported name of the attribute or element.
*/
TransformedEvent(final E event, final QName name) {
- this.event = event;
- this.name = name;
+ this.event = event;
+ this.name = name;
}
@Override public boolean isStartElement() {return false;}
@@ -128,14 +128,16 @@ abstract class TransformedEvent<E extend
/**
* Wrapper over a namespace emitted during the reading or writing of an
XML document.
- * This wrapper is used for changing the namespace URI.
+ * This wrapper is used for changing the namespace URI. The wrapped {@link
#event}
+ * should be a {@link Namespace}, but this class accepts also the {@link
Attribute}
+ * super-type for allowing the {@link Type} attribute to create synthetic
namespaces.
*/
- static final class NS extends TransformedEvent<Namespace> implements
Namespace {
+ static final class NS extends TransformedEvent<Attribute> implements
Namespace {
/** The URI of the namespace. */
private final String namespaceURI;
/** Wraps the given event with a different prefix and URI. */
- NS(final Namespace event, final String prefix, final String
namespaceURI) {
+ NS(final Attribute event, final String prefix, final String
namespaceURI) {
super(event, new QName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
prefix, XMLConstants.XMLNS_ATTRIBUTE));
this.namespaceURI = namespaceURI;
}
@@ -145,7 +147,7 @@ abstract class TransformedEvent<E extend
@Override public String getNamespaceURI() {return
namespaceURI;}
@Override public String getValue() {return
namespaceURI;}
@Override public String getDTDType() {return
event.getDTDType();}
- @Override public boolean isSpecified() {return
event.isSpecified();}
+ @Override public boolean isSpecified() {return
event instanceof Namespace && event.isSpecified();}
@Override public String getPrefix() {return
(name != null) ? name.getLocalPart() : null;}
@Override public boolean isDefaultNamespaceDeclaration() {return
(name != null) && name.getLocalPart().isEmpty();}
@Override void write(final Appendable out) throws IOException {
@@ -175,23 +177,29 @@ abstract class TransformedEvent<E extend
@Override public String getDTDType() {return
event.getDTDType();}
@Override public boolean isSpecified() {return
event.isSpecified();}
@Override void write(final Appendable out) throws IOException {
- name(out).append("=\"").append(event.getValue()).append('"');
+ name(out).append("=\"").append(getValue()).append('"');
}
}
/**
- * The attribute for {@code "xsi:type"}.
+ * The {@code "xsi:type"} attribute. Contrarily to other attributes, the
name is unchanged compared
+ * to the original attribute; instead the value is different. Even in
unchanged, the {@link QName}
+ * is specified at construction time because it is required by the parent
class.
*/
- static final class TypeAttr extends Attr {
+ static final class Type extends Attr {
/** The attribute value. */
private final String value;
- /** Wraps the given event with a different name. */
- TypeAttr(final Attribute event, final QName name, final String value) {
+ /** If the value requires a new prefix to be bound, the namespace
declaration for it. */
+ Namespace namespace;
+
+ /** Wraps the given event with a different value. */
+ Type(final Attribute event, final QName name, final String value) {
super(event, name);
this.value = value;
}
+ /** Returns the {@code "xsi:type"} attribute value. */
@Override public String getValue() {return value;}
}
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -310,7 +310,7 @@ abstract class Transformer {
}
/**
- * Imports or exports an attribute read or write from/to the XML document.
+ * 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 {@code "xsi:type"}
attribute:
* its value is parsed as a name and converted.
@@ -320,29 +320,40 @@ abstract class Transformer {
if ("type".equals(originalName.getLocalPart()) &&
Namespaces.XSI.equals(originalName.getNamespaceURI())) {
/*
* In the special case of "xsi:type", do not convert the attribute
name.
- * Instead, parse and convert the attribute value.
+ * Instead, parse and convert the attribute value. For example in
the following:
+ *
+ * <cit:title xsi:type="lan:PT_FreeText_PropertyType">
+ *
+ * The "lan" prefix needs to be changed to "gmd" if exporting to
legacy ISO 19139:2007.
*/
final String value = attribute.getValue();
if (value != null) {
final int s = value.indexOf(':');
if (s >= 0) {
- String prefix = value.substring(0, s);
- String ns = namespaces.get(prefix);
- if (ns != null) {
- String localPart = value.substring(s+1);
- final Map<String,String> renaming =
renamingMap().get(localPart);
- if (renaming != null) {
- QName name = new QName(ns, localPart, prefix);
- final Map<String,String> currentMap =
outerElementProperties;
- outerElementProperties = renaming;
- name = convert(name);
- outerElementProperties = currentMap;
+ String prefix = value.substring(0, s).trim();
+ String namespace = namespaces.get(prefix);
+ if (namespace != null) {
+ String localPart = value.substring(s+1).trim();
+ QName name = new QName(namespace, localPart, prefix);
+ final Map<String,String> currentMap =
outerElementProperties;
+ outerElementProperties =
renamingMap().getOrDefault(localPart, Collections.emptyMap());
+ final boolean changed = (name != (name =
convert(name)));
+ outerElementProperties = currentMap;
+ if (changed) {
prefix = name.getPrefix();
localPart = name.getLocalPart();
- final String exported = prefix + ':' + localPart;
- if (!exported.equals(value)) {
- return new
TransformedEvent.TypeAttr(attribute, originalName, exported);
+ namespace = name.getNamespaceURI();
+ TransformedEvent.Type rt = new
TransformedEvent.Type(
+ attribute, originalName, prefix + ':' +
localPart);
+ /*
+ * At this point we got the new value. For example
"gmd:PT_FreeText_PropertyType" may
+ * have been replaced by
"lan:PT_FreeText_PropertyType". However we need to verify if
+ * the "lan" prefix has been bound to a namespace,
otherwise the parsing will fail.
+ */
+ if (!namespace.equals(namespaces.get(prefix))) {
+ rt.namespace = new
TransformedEvent.NS(attribute, prefix, namespace);
}
+ return rt;
}
}
}
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingReader.java
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -222,21 +222,43 @@ final class TransformingReader extends T
case START_ELEMENT: {
final StartElement e = event.asStartElement();
final QName originalName = e.getName();
- open(originalName); // Must be invoked
before 'convert(QName)'.
- final QName name = convert(originalName);
- boolean changed = name != originalName;
+ open(originalName); // Must be
invoked before 'convert(QName)'.
+ final QName name = convert(originalName); // Name in the
transformed XML document.
+ boolean changed = name != originalName; // Whether the
name or an attribute changed.
+ Namespace localNS = null; // Additional
namespace required by "xsi:type".
for (final Iterator<Attribute> it = e.getAttributes();
it.hasNext();) {
final Attribute a = it.next();
final Attribute ae = convert(a);
- changed |= (a != ae);
renamedAttributes.add(ae);
+ if (a != ae) {
+ changed = true;
+ if (localNS == null && ae instanceof
TransformedEvent.Type) {
+ localNS = ((TransformedEvent.Type) ae).namespace;
+ }
+ }
}
- final List<Namespace> namespaces = importNS(e.getNamespaces(),
+ /*
+ * The list of namespaces is determined by the "xmlns:foo"
attributes, which are handled in a
+ * special way. This list is typically non-empty only in the
root element, but it is legal to
+ * have namespace declaration in non-root elements as well.
+ *
+ * Special case: if this element contains a "xsi:type"
attribute and if we changed its value
+ * (for example from "gmd:PT_FreeText_PropertyType" to
"lan:PT_FreeText_PropertyType"), then
+ * we may need to add an extra namespace declaration (e.g. for
the "lan" prefix).
+ */
+ List<Namespace> namespaces = importNS(e.getNamespaces(),
originalName.getNamespaceURI(),
name.getNamespaceURI(), changed);
if (namespaces != null) {
+ if (localNS != null) {
+ if (namespaces.isEmpty()) {
+ namespaces = Collections.singletonList(localNS);
+ } else {
+ namespaces.add(localNS);
+ }
+ }
event = new TransformedEvent.Start(e, name, namespaces,
attributes(), version);
} else {
- renamedAttributes.clear();
+ renamedAttributes.clear(); // Note: above call to
attributes() also cleared that list.
}
break;
}
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/xml/TransformingWriter.java
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -379,7 +379,7 @@ final class TransformingWriter extends T
if (namespaces != null) {
event = new Event(e, name, namespaces, attributes(),
version);
} else {
- renamedAttributes.clear();
+ renamedAttributes.clear(); // Note: above call to
attributes() also cleared that list.
}
/*
* At this point, we finished to export the event (i.e. to
convert namespaces to the URI
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnExport.lst
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -3,6 +3,7 @@
# Lines with zero-space indentation are namespace URIs.
# Lines with one-space indentation are XML types.
# Lines with two-spaces indentation are properties.
+# actual/exported means that a property needs to be renamed.
#
http://www.isotc211.org/2005/gmd
MD_Georectified
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/resources/org/apache/sis/xml/RenameOnImport.lst
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -1,7 +1,7 @@
#
# Namespaces in which attribute are defined.
# Lines with zero-space indentation are namespace URIs.
-# Lines with one-space indentation are XML types.
+# Lines with one-space indentation are XML types.
# Lines with two-spaces indentation are properties.
# old/new means that a property needs to be renamed.
#
Modified:
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/FreeTextMarshallingTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/FreeTextMarshallingTest.java?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/FreeTextMarshallingTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/FreeTextMarshallingTest.java
[UTF-8] Sun Apr 15 17:51:32 2018
@@ -20,8 +20,9 @@ import java.util.Locale;
import javax.xml.bind.JAXBException;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.util.iso.DefaultInternationalString;
-import org.apache.sis.test.XMLTestCase;
+import org.apache.sis.internal.jaxb.LegacyNamespaces;
import org.apache.sis.xml.Namespaces;
+import org.apache.sis.test.XMLTestCase;
import org.junit.Test;
import static org.apache.sis.test.MetadataAssert.*;
@@ -52,7 +53,42 @@ public final strictfp class FreeTextMars
}
/**
- * Tests parsing of a free text in an ISO 19139-compliant way.
+ * Tests parsing of a free text in an ISO 19139 compliant way.
+ * The free text is wrapped inside a citation for marshalling
+ * purpose, but only the free text is actually tested.
+ *
+ * @throws JAXBException if the XML in this test can not be parsed by JAXB.
+ */
+ @Test
+ public void testLegacy() throws JAXBException {
+ final String expected =
+ "<gmd:CI_Citation xmlns:gmd=\"" + LegacyNamespaces.GMD + '"'
+ + " xmlns:gco=\"" + LegacyNamespaces.GCO + '"'
+ + " xmlns:xsi=\"" + Namespaces.XSI + "\">\n" +
+ " <gmd:title xsi:type=\"gmd:PT_FreeText_PropertyType\">\n" +
+ " <gco:CharacterString>OpenSource
Project</gco:CharacterString>\n" +
+ " <gmd:PT_FreeText>\n" +
+ " <gmd:textGroup>\n" +
+ " <gmd:LocalisedCharacterString
locale=\"#locale-eng\">OpenSource Project</gmd:LocalisedCharacterString>\n" +
+ " </gmd:textGroup>\n" +
+ " <gmd:textGroup>\n" +
+ " <gmd:LocalisedCharacterString
locale=\"#locale-ita\">Progetto OpenSource</gmd:LocalisedCharacterString>\n" +
+ " </gmd:textGroup>\n" +
+ " <gmd:textGroup>\n" +
+ " <gmd:LocalisedCharacterString
locale=\"#locale-fra\">Projet OpenSource</gmd:LocalisedCharacterString>\n" +
+ " </gmd:textGroup>\n" +
+ " </gmd:PT_FreeText>\n" +
+ " </gmd:title>\n" +
+ "</gmd:CI_Citation>\n";
+
+ final Citation citation = unmarshal(Citation.class, expected);
+ assertEquals(getExpectedI18N(), citation.getTitle());
+ final String actual = marshal(citation, VERSION_2007);
+ assertXmlEquals(expected, actual, "xmlns:*");
+ }
+
+ /**
+ * Tests parsing of a free text in an ISO 19115-3 compliant way.
* The free text is wrapped inside a citation for marshalling
* purpose, but only the free text is actually tested.
*
@@ -88,7 +124,7 @@ public final strictfp class FreeTextMars
}
/**
- * Tests parsing of a free text in the legacy (pre-Geotk 3.17) format.
+ * Tests parsing of a free text in a non-standard variant.
* We continue to support this format for compatibility reason, but
* also because it is more compact and closer to what we would expect
* inside a {@code <textGroup>} node.
@@ -96,7 +132,7 @@ public final strictfp class FreeTextMars
* @throws JAXBException if the XML in this test can not be parsed by JAXB.
*/
@Test
- public void testLegacy() throws JAXBException {
+ public void testNonStandard() throws JAXBException {
final String legacy =
"<cit:CI_Citation xmlns:lan=\"" + Namespaces.LAN + '"'
+ " xmlns:cit=\"" + Namespaces.CIT + '"'
Modified:
sis/branches/JDK8/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/PositionalAccuracy.xml
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/PositionalAccuracy.xml?rev=1829214&r1=1829213&r2=1829214&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/PositionalAccuracy.xml
(original)
+++
sis/branches/JDK8/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/PositionalAccuracy.xml
Sun Apr 15 17:51:32 2018
@@ -21,7 +21,6 @@
<gmd:DQ_RelativeInternalPositionalAccuracy
xmlns:gmd = "http://www.isotc211.org/2005/gmd"
xmlns:gco = "http://www.isotc211.org/2005/gco"
- xmlns:lan = "http://standards.iso.org/iso/19115/-3/lan/1.0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.isotc211.org/2005/gmd
http://schemas.opengis.net/iso/19139/20070417/gmd/gmd.xsd">