Author: desruisseaux Date: Fri Jul 3 17:37:53 2015 New Revision: 1689049 URL: http://svn.apache.org/r1689049 Log: WKT 2: implement parsing of CoordinateOperation (missing only the call to a factory method).
Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1689049&r1=1689048&r2=1689049&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] Fri Jul 3 17:37:53 2015 @@ -357,6 +357,27 @@ final class GeodeticObjectParser extends } /** + * Parses a coordinate reference system wrapped in an element of the given name. + * + * @param parent The parent element containing the CRS to parse. + * @param mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}. + * @param keyword "SourceCRS", "TargetCRS" or "InterpolationCRS". + * @return The coordinate reference system, or {@code null} if none. + * @throws ParseException if the CRS can not be parsed. + */ + private CoordinateReferenceSystem parseCoordinateReferenceSystem(final Element parent, final int mode, + final String keyword) throws ParseException + { + final Element element = parent.pullElement(mode, keyword); + if (element == null) { + return null; + } + final CoordinateReferenceSystem crs = parseCoordinateReferenceSystem(element, true); + element.close(ignoredElements); + return crs; + } + + /** * Returns the value associated to {@link IdentifiedObject#IDENTIFIERS_KEY} as an {@code Identifier} object. * This method shall accept all value types that {@link #parseMetadataAndClose(Element, Object)} may store. * @@ -1157,6 +1178,43 @@ final class GeodeticObjectParser extends } /** + * Parses a {@code "Method"} (WKT 2) element, without the parameters. + * + * @param parent The parent element. + * @param keywords The element keywords. + * @return The operation method. + * @throws ParseException if the {@code "Method"} element can not be parsed. + */ + private OperationMethod parseMethod(final Element parent, final String... keywords) throws ParseException { + final Element element = parent.pullElement(MANDATORY, keywords); + final String name = element.pullString("method"); + Map<String,?> properties = parseMetadataAndClose(element, name, null); + final Identifier id = toIdentifier(properties.remove(IdentifiedObject.IDENTIFIERS_KEY)); // See NOTE 2 in parseDerivingConversion. + /* + * The map projection method may be specified by an EPSG identifier (or any other authority), + * which is preferred to the method name since the later is potentially ambiguous. However not + * all CoordinateOperationFactory may accept identifier as an argument to 'getOperationMethod'. + * So if an identifier is present, we will try to use it but fallback on the name if we can + * not use the identifier. + */ + FactoryException suppressed = null; + if (id != null) try { + // CodeSpace is a mandatory attribute in ID[…] elements, so we do not test for null values. + return opFactory.getOperationMethod(id.getCodeSpace() + DefaultNameSpace.DEFAULT_SEPARATOR + id.getCode()); + } catch (FactoryException e) { + suppressed = e; + } + try { + return opFactory.getOperationMethod(name); + } catch (FactoryException e) { + if (suppressed != null) { + e.addSuppressed(suppressed); + } + throw element.parseFailed(e); + } + } + + /** * Parses a {@code "Method"} (WKT 2) element, followed by parameter values. The syntax is given by * <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#62">WKT 2 specification §9.3</a>. * @@ -1195,25 +1253,8 @@ final class GeodeticObjectParser extends } name = parent.pullString("name"); } - final Element element = parent.pullElement(MANDATORY, WKTKeywords.Method, WKTKeywords.Projection); - final String methodName = element.pullString("method"); - Map<String,?> properties = parseMetadataAndClose(element, methodName, null); - final Identifier id = toIdentifier(properties.remove(IdentifiedObject.IDENTIFIERS_KEY)); // See NOTE 2. - /* - * The map projection method may be specified by an EPSG identifier (or any other authority), - * which is preferred to the method name since the later is potentially ambiguous. However not - * all CoordinateOperationFactory may accept identifier as an argument to 'getOperationMethod'. - * So if an identifier is present, we will try to use it but fallback on the name if we can - * not use the identifier. - */ - OperationMethod method = null; - FactoryException suppressed = null; - if (id != null) try { - // CodeSpace is a mandatory attribute in ID[…] elements, so we do not test for null values. - method = opFactory.getOperationMethod(id.getCodeSpace() + DefaultNameSpace.DEFAULT_SEPARATOR + id.getCode()); - } catch (FactoryException e) { - suppressed = e; - } + OperationMethod method = parseMethod(parent, WKTKeywords.Method, WKTKeywords.Projection); + Map<String,?> properties = this.properties; // Same properties then OperationMethod, with ID removed. /* * Set the list of parameters. * @@ -1224,32 +1265,26 @@ final class GeodeticObjectParser extends * but we shall not inherit the OperationMethod identifier. This is the reason why we invoked * properties.remove(IdentifiedObject.IDENTIFIERS_KEY)) above. */ + final ParameterValueGroup parameters = method.getParameters().createValue(); + parseParameters(parent, parameters, defaultUnit, defaultAngularUnit); + if (wrapper != null) { + properties = parseMetadataAndClose(parent, name, method); + /* + * DEPARTURE FROM ISO 19162: the specification in §9.3.2 said: + * + * "If an identifier is provided as an attribute within the <map projection conversion> object, + * because it is expected to describe a complete collection of zone name, method, parameters and + * parameter values, it shall override any identifiers given within the map projection method and + * map projection parameter objects." + * + * However this would require this GeodeticObjectParser to hold a CoordinateOperationAuthorityFactory, + * which we do not yet implement. See https://issues.apache.org/jira/browse/SIS-210 + */ + } try { - if (method == null) { - method = opFactory.getOperationMethod(methodName); - } - final ParameterValueGroup parameters = method.getParameters().createValue(); - parseParameters(parent, parameters, defaultUnit, defaultAngularUnit); - if (wrapper != null) { - properties = parseMetadataAndClose(parent, name, method); - /* - * DEPARTURE FROM ISO 19162: the specification in §9.3.2 said: - * - * "If an identifier is provided as an attribute within the <map projection conversion> object, - * because it is expected to describe a complete collection of zone name, method, parameters and - * parameter values, it shall override any identifiers given within the map projection method and - * map projection parameter objects." - * - * However this would require this GeodeticObjectParser to hold a CoordinateOperationAuthorityFactory, - * which we do not yet implement. See https://issues.apache.org/jira/browse/SIS-210 - */ - } return opFactory.createDefiningConversion(properties, method, parameters); } catch (FactoryException exception) { - if (suppressed != null) { - exception.addSuppressed(suppressed); - } - throw element.parseFailed(exception); + throw parent.parseFailed(exception); } } @@ -1935,8 +1970,10 @@ final class GeodeticObjectParser extends } /** - * Parses a {@code "COMPD_CS"} element. - * This element has the following pattern: + * Parses a {@code "CompoundCRS"} element. The syntax is given by + * <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#110">WKT 2 specification §16</a>. + * + * The legacy WKT 1 specification was: * * {@preformat text * COMPD_CS["<name>", <head cs>, <tail cs> {,<authority>}] @@ -1944,8 +1981,8 @@ final class GeodeticObjectParser extends * * @param mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}. * @param parent The parent element. - * @return The {@code "COMPD_CS"} element as a {@link CompoundCRS} object. - * @throws ParseException if the {@code "COMPD_CS"} element can not be parsed. + * @return The {@code "CompoundCRS"} element as a {@link CompoundCRS} object. + * @throws ParseException if the {@code "CompoundCRS"} element can not be parsed. */ private CompoundCRS parseCompoundCRS(final int mode, final Element parent) throws ParseException { final Element element = parent.pullElement(mode, WKTKeywords.CompoundCRS, WKTKeywords.Compd_CS); @@ -2023,7 +2060,33 @@ final class GeodeticObjectParser extends } } + /** + * Parses a {@code "CoordinateOperation"} element. The syntax is given by + * <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#113">WKT 2 specification §17</a>. + * + * @param mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}. + * @param parent The parent element. + * @return The {@code "CoordinateOperation"} element as a {@link CoordinateOperation} object. + * @throws ParseException if the {@code "CoordinateOperation"} element can not be parsed. + */ private CoordinateOperation parseOperation(final int mode, final Element parent) throws ParseException { + final Element element = parent.pullElement(mode, WKTKeywords.CoordinateOperation); + if (element == null) { + return null; + } + final String name = element.pullString("name"); + final CoordinateReferenceSystem sourceCRS = parseCoordinateReferenceSystem(element, MANDATORY, WKTKeywords.SourceCRS); + final CoordinateReferenceSystem targetCRS = parseCoordinateReferenceSystem(element, MANDATORY, WKTKeywords.TargetCRS); + final CoordinateReferenceSystem interpolationCRS = parseCoordinateReferenceSystem(element, OPTIONAL, WKTKeywords.InterpolationCRS); + final OperationMethod method = parseMethod(parent, WKTKeywords.Method); + final Element accuracy = parent.pullElement(OPTIONAL, WKTKeywords.OperationAccuracy); + final Map<String,Object> properties = parseMetadataAndClose(parent, name, method); + final ParameterValueGroup parameters = method.getParameters().createValue(); + parseParameters(parent, parameters, null, null); + if (accuracy != null) { + accuracy.pullDouble("accuracy"); // TODO: share the code from EPSG factory. + accuracy.close(ignoredElements); + } return null; // Not yet implemented. } }