sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1686050 - in /sis/branches/JDK8/core/sis-metadata/src: main/java/org/apache/sis/internal/metadata/ main/java/org/apache/sis/io/wkt/ test/java/org/apache/sis/io/wkt/
Date Wed, 17 Jun 2015 15:10:57 GMT
Author: desruisseaux
Date: Wed Jun 17 15:10:56 2015
New Revision: 1686050

URL: http://svn.apache.org/r1686050
Log:
WKT 2: refactoring of the parser in order to have better control on mandatory and optional elements.

Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
    sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java?rev=1686050&r1=1686049&r2=1686050&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] Wed Jun 17 15:10:56 2015
@@ -97,6 +97,7 @@ public final class WKTKeywords extends S
             Datum       = "Datum",
             GeodeticCRS = "GeodeticCRS",
             BaseGeodCRS = "BaseGeodCRS",
+            GeodCRS     = "GeodCRS",
             GeogCS      = "GeogCS",
             GeocCS      = "GeocCS";
 

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java?rev=1686050&r1=1686049&r2=1686050&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java [UTF-8] Wed Jun 17 15:10:56 2015
@@ -55,6 +55,26 @@ import static org.apache.sis.util.Argume
  */
 abstract class AbstractParser implements Parser {
     /**
+     * A mode for the {@link Element#pullElement(int, String...)} method meaning that only the first element
+     * should be checked. If the name of the first element does not match one of the specified names, then
+     * {@code pullElement(…)} returns {@code null}.
+     */
+    static final int FIRST = 0;
+
+    /**
+     * A mode for the {@link Element#pullElement(int, String...)} method meaning that the requested element
+     * is optional but is not necessarily first. If no element have a name matching one of the requested names,
+     * then {@code pullElement(…)} returns {@code null}.
+     */
+    static final int OPTIONAL = 1;
+
+    /**
+     * A mode for the {@link Element#pullElement(int, String...)} method meaning that an exception shall be
+     * thrown if no element have a name matching one of the requested names.
+     */
+    static final int MANDATORY = 2;
+
+    /**
      * Set to {@code true} if parsing of number in scientific notation is allowed.
      * The way to achieve that is currently a hack, because {@link NumberFormat}
      * has no API for managing that as of JDK 1.8.

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java?rev=1686050&r1=1686049&r2=1686050&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] Wed Jun 17 15:10:56 2015
@@ -289,19 +289,6 @@ final class Element {
     ////////////////////////////////////////////////////////////////////////////////////////
 
     /**
-     * Returns a {@link ParseException} for a child keyword which is unknown.
-     *
-     * @param  child The unknown child keyword, or {@code null}.
-     * @return The exception to be thrown.
-     */
-    final ParseException keywordNotFound(String child) {
-        if (child == null) {
-            child = "";
-        }
-        return new LocalizedParseException(locale, Errors.Keys.UnknownKeyword_1, new String[] {child}, offset);
-    }
-
-    /**
      * Returns a {@link ParseException} with the specified cause. A localized string
      * <code>"Error in &lt;{@link #keyword}&gt;"</code> will be prepend to the message.
      * The error index will be the starting index of this {@code Element}.
@@ -365,6 +352,34 @@ final class Element {
                 new String[] {keyword, key}, error);
     }
 
+    /**
+     * Returns a {@link ParseException} for a child keyword which is unknown.
+     *
+     * @param  expected Keyword of a typical element. Used only if this element contains no child element.
+     * @return The exception to be thrown.
+     */
+    final ParseException missingOrUnknownComponent(final String expected) {
+        String name = null;
+        for (final Object child : list) {
+            if (child instanceof Element) {
+                name = ((Element) child).keyword;
+                if (name != null) {
+                    break;
+                }
+            }
+        }
+        final short res;
+        final String[] args;
+        if (name != null) {
+            res  = Errors.Keys.UnknownKeyword_1;
+            args = new String[] {name};
+        } else {
+            res  = Errors.Keys.MissingComponentInElement_2;
+            args = new String[] {keyword, expected};
+        }
+        return new LocalizedParseException(locale, res, args, offset);
+    }
+
 
 
 
@@ -494,29 +509,24 @@ final class Element {
     }
 
     /**
-     * Removes the next {@link Element} from the list and returns it.
-     * If the parameter is missing, then the first element in the given {@code keys} array
-     * will be taken as the name of the missing element to report in the exception message.
-     *
-     * @param  keys The element names (e.g. {@code "PrimeMeridian"}).
-     * @return The next {@link Element} on the list.
-     * @throws ParseException if no more element is available.
-     */
-    public Element pullElement(final String... keys) throws ParseException {
-        final Element element = pullOptionalElement(keys);
-        if (element != null) {
-            return element;
-        }
-        throw missingComponent(keys[0]);
-    }
-
-    /**
-     * Removes the next {@link Element} from the list and returns it.
+     * Removes the next {@link Element} of the given name from the list and returns it.
+     * If the element was mandatory but is missing, then the first entry in the given {@code keys}
+     * array will be taken as the name of the missing element to report in the exception message.
+     *
+     * <p>The given {@code mode} argument can be one of the following constants:</p>
+     * <ul>
+     *   <li>{@link AbstractParser#MANDATORY} throw an exception if no matching element is found.</li>
+     *   <li>{@link AbstractParser#OPTIONAL} return {@code null} if no matching element is found.</li>
+     *   <li>{@link AbstractParser#FIRST} return {@code null} if the first element (ignoring all others)
+     *       does not match.</li>
+     * </ul>
      *
+     * @param  mode {@link AbstractParser#FIRST}, {@link AbstractParser#OPTIONAL} or {@link AbstractParser#MANDATORY}.
      * @param  keys The element names (e.g. {@code "PrimeMeridian"}).
-     * @return The next {@link Element} on the list, or {@code null} if no more element is available.
+     * @return The next {@link Element} of the given names found on the list, or {@code null} if none.
+     * @throws ParseException if {@code mode} is {@code MANDATORY} and no element of the given names was found.
      */
-    public Element pullOptionalElement(final String... keys) {
+    public Element pullElement(final int mode, final String... keys) throws ParseException {
         final Iterator<Object> iterator = list.iterator();
         while (iterator.hasNext()) {
             final Object object = iterator.next();
@@ -530,10 +540,16 @@ final class Element {
                             return element;
                         }
                     }
+                    if (mode == AbstractParser.FIRST) {
+                        return null;
+                    }
                 }
             }
         }
-        return null;
+        if (mode != AbstractParser.MANDATORY) {
+            return null;
+        }
+        throw missingComponent(keys[0]);
     }
 
     /**
@@ -579,16 +595,6 @@ final class Element {
     }
 
     /**
-     * Returns the next element, or {@code null} if there is no more element.
-     * The element is <strong>not</strong> removed from the list.
-     *
-     * @return The next element, or {@code null} if there is no more elements.
-     */
-    public Object peek() {
-        return list.isEmpty() ? null : list.getFirst();
-    }
-
-    /**
      * Returns {@code true} if this element does not contains any remaining child.
      *
      * @return {@code true} if there is no child remaining.

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=1686050&r1=1686049&r2=1686050&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] Wed Jun 17 15:10:56 2015
@@ -198,12 +198,12 @@ final class GeodeticObjectParser extends
             final ObjectFactory factories, final MathTransformFactory mtFactory)
     {
         super(Symbols.getDefault(), null, null, null, mtFactory, (Locale) defaultProperties.get(Errors.LOCALE_KEY));
-        crsFactory    = (CRSFactory)   factories;
-        csFactory     = (CSFactory)    factories;
-        datumFactory  = (DatumFactory) factories;
-        referencing   = ReferencingServices.getInstance();
-        opFactory     = referencing.getCoordinateOperationFactory(defaultProperties, mtFactory);
-        convention    = Convention.DEFAULT;
+        crsFactory   = (CRSFactory)   factories;
+        csFactory    = (CSFactory)    factories;
+        datumFactory = (DatumFactory) factories;
+        referencing  = ReferencingServices.getInstance();
+        opFactory    = referencing.getCoordinateOperationFactory(defaultProperties, mtFactory);
+        convention   = Convention.DEFAULT;
     }
 
     /**
@@ -309,21 +309,20 @@ final class GeodeticObjectParser extends
         if (value != null) {
             return value;
         }
-        String keyword = null;
-        final Object child = element.peek();
-        if (child instanceof Element) {
-            keyword = ((Element) child).keyword;
-            if (keyword != null) {
-                if (keyword.equalsIgnoreCase(WKTKeywords.Axis))        return parseAxis      (element, false, SI.METRE, true);
-                if (keyword.equalsIgnoreCase(WKTKeywords.PrimeM))      return parsePrimem    (element, NonSI.DEGREE_ANGLE);
-                if (keyword.equalsIgnoreCase(WKTKeywords.ToWGS84))     return parseToWGS84   (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Spheroid))    return parseSpheroid  (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Vert_Datum))  return parseVertDatum (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Local_Datum)) return parseLocalDatum(element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Datum))       return parseDatum     (element, referencing.getGreenwich());
-            }
+        Object object;
+        if ((object = parseAxis             (FIRST, element, false, SI.METRE)) == null &&
+            (object = parsePrimeMeridian    (FIRST, element, NonSI.DEGREE_ANGLE)) == null &&
+            (object = parseDatum            (FIRST, element, null)) == null &&
+            (object = parseEllipsoid        (FIRST, element)) == null &&
+            (object = parseToWGS84          (FIRST, element)) == null &&
+            (object = parseVerticalDatum    (FIRST, element)) == null &&
+            (object = parseTimeDatum        (FIRST, element)) == null &&
+            (object = parseEngineeringDatum (FIRST, element)) == null &&
+            (object = parseProjection       (FIRST, element, SI.METRE, NonSI.DEGREE_ANGLE)) == null)
+        {
+            throw element.missingOrUnknownComponent(WKTKeywords.GeodeticCRS);
         }
-        throw element.keywordNotFound(keyword);
+        return object;
     }
 
     /**
@@ -337,25 +336,21 @@ final class GeodeticObjectParser extends
     private CoordinateReferenceSystem parseCoordinateReferenceSystem(final Element element, final boolean mandatory)
             throws ParseException
     {
-        String keyword = null;
-        final Object child = element.peek();
-        if (child instanceof Element) {
-            keyword = ((Element) child).keyword;
-            if (keyword != null) {
-                if (keyword.equalsIgnoreCase(WKTKeywords.GeogCS))    return parseGeoGCS  (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.ProjCS))    return parseProjCS  (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.GeocCS))    return parseGeoCCS  (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Vert_CS))   return parseVertCS  (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.TimeCRS))   return parseTimeCRS (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Local_CS))  return parseLocalCS (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Compd_CS))  return parseCompdCS (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Fitted_CS)) return parseFittedCS(element);
+        CoordinateReferenceSystem crs;
+        if ((crs = parseGeographicCRS  (FIRST, element)) == null &&
+            (crs = parseProjectedCRS   (FIRST, element)) == null &&
+            (crs = parseGeocentricCRS  (FIRST, element)) == null &&
+            (crs = parseVerticalCRS    (FIRST, element)) == null &&
+            (crs = parseTimeCRS        (FIRST, element)) == null &&
+            (crs = parseEngineeringCRS (FIRST, element)) == null &&
+            (crs = parseCompoundCRS    (FIRST, element)) == null &&
+            (crs = parseFittedCS       (FIRST, element)) == null)
+        {
+            if (mandatory) {
+                throw element.missingOrUnknownComponent(WKTKeywords.GeodeticCRS);
             }
         }
-        if (mandatory) {
-            throw element.keywordNotFound(keyword);
-        }
-        return null;
+        return crs;
     }
 
     /**
@@ -377,11 +372,11 @@ final class GeodeticObjectParser extends
         properties.clear();
         properties.put(IdentifiedObject.NAME_KEY, name);
         Element element;
-        while ((element = parent.pullOptionalElement(WKTKeywords.Id, WKTKeywords.Authority)) != null) {
+        while ((element = parent.pullElement(OPTIONAL, WKTKeywords.Id, WKTKeywords.Authority)) != null) {
             final String   codeSpace = element.pullString("name");
             final String   code      = element.pullObject("code").toString();   // Accepts Integer as well as String.
             final Object   version   = element.pullOptional(Object.class);      // Accepts Number as well as String.
-            final Element  citation  = element.pullOptionalElement(WKTKeywords.Citation);
+            final Element  citation  = element.pullElement(OPTIONAL, WKTKeywords.Citation);
             final String   authority;
             if (citation != null) {
                 authority = citation.pullString("authority");
@@ -389,7 +384,7 @@ final class GeodeticObjectParser extends
             } else {
                 authority = codeSpace;
             }
-            final Element uri = element.pullOptionalElement(WKTKeywords.URI);
+            final Element uri = element.pullElement(OPTIONAL, WKTKeywords.URI);
             if (uri != null) {
                 uri.pullString("URI");      // TODO: not yet stored, since often redundant with other informations.
                 uri.close(ignoredElements);
@@ -436,7 +431,7 @@ final class GeodeticObjectParser extends
             /*
              * Example: SCOPE["Large scale topographic mapping and cadastre."]
              */
-            element = parent.pullOptionalElement(WKTKeywords.Scope);
+            element = parent.pullElement(OPTIONAL, WKTKeywords.Scope);
             if (element != null) {
                 properties.put(ReferenceSystem.SCOPE_KEY, element.pullString("scope"));  // Other types like Datum use the same key.
                 element.close(ignoredElements);
@@ -445,7 +440,7 @@ final class GeodeticObjectParser extends
              * Example: AREA["Netherlands offshore."]
              */
             DefaultExtent extent = null;
-            while ((element = parent.pullOptionalElement(WKTKeywords.Area)) != null) {
+            while ((element = parent.pullElement(OPTIONAL, WKTKeywords.Area)) != null) {
                 final String area = element.pullString("area");
                 element.close(ignoredElements);
                 if (extent == null) extent = new DefaultExtent();
@@ -454,7 +449,7 @@ final class GeodeticObjectParser extends
             /*
              * Example: BBOX[51.43, 2.54, 55.77, 6.40]
              */
-            while ((element = parent.pullOptionalElement(WKTKeywords.BBox)) != null) {
+            while ((element = parent.pullElement(OPTIONAL, WKTKeywords.BBox)) != null) {
                 final double southBoundLatitude = element.pullDouble("southBoundLatitude");
                 final double westBoundLongitude = element.pullDouble("westBoundLongitude");
                 final double northBoundLatitude = element.pullDouble("northBoundLatitude");
@@ -469,7 +464,7 @@ final class GeodeticObjectParser extends
              *
              * Units are optional, default to metres (no "contextual units" here).
              */
-            while ((element = parent.pullOptionalElement(WKTKeywords.VerticalExtent)) != null) {
+            while ((element = parent.pullElement(OPTIONAL, WKTKeywords.VerticalExtent)) != null) {
                 final double minimum = element.pullDouble("minimum");
                 final double maximum = element.pullDouble("maximum");
                 Unit<Length> unit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
@@ -487,7 +482,7 @@ final class GeodeticObjectParser extends
              * This operation requires the the sis-temporal module. If not available,
              * we will report a warning and leave the temporal extent missing.
              */
-            while ((element = parent.pullOptionalElement(WKTKeywords.TimeExtent)) != null) {
+            while ((element = parent.pullElement(OPTIONAL, WKTKeywords.TimeExtent)) != null) {
                 final Date startTime = element.pullDate("startTime");
                 final Date endTime   = element.pullDate("endTime");
                 element.close(ignoredElements);
@@ -503,7 +498,7 @@ final class GeodeticObjectParser extends
             /*
              * Example: REMARK["Замечание на русском языке"]
              */
-            element = parent.pullOptionalElement(WKTKeywords.Remark);
+            element = parent.pullElement(OPTIONAL, WKTKeywords.Remark);
             if (element != null) {
                 properties.put(IdentifiedObject.REMARKS_KEY, element.pullString("remarks"));
                 element.close(ignoredElements);
@@ -536,7 +531,7 @@ final class GeodeticObjectParser extends
     private <Q extends Quantity> Unit<Q> parseDerivedUnit(final Element parent,
             final String keyword, final Unit<Q> baseUnit) throws ParseException
     {
-        final Element element = parent.pullOptionalElement(keyword, WKTKeywords.Unit);
+        final Element element = parent.pullElement(OPTIONAL, keyword, WKTKeywords.Unit);
         if (element == null) {
             return null;
         }
@@ -555,7 +550,7 @@ final class GeodeticObjectParser extends
      * @throws ParseException if the {@code "UNIT"} can not be parsed.
      */
     private Unit<?> parseUnit(final Element parent) throws ParseException {
-        final Element element = parent.pullOptionalElement(UNIT_KEYWORDS);
+        final Element element = parent.pullElement(OPTIONAL, UNIT_KEYWORDS);
         if (element == null) {
             return null;
         }
@@ -583,25 +578,20 @@ final class GeodeticObjectParser extends
      * to make the parser more tolerant to non-100% compliant WKT. Note that AXIS is really the only element without
      * such AUTHORITY clause and the EPSG database provides authority code for all axis.</div>
      *
+     * @param  mode         {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent       The parent element.
      * @param  isGeographic {@code true} if the parent element is a geodetic CRS having an ellipsoidal coordinate system.
      * @param  defaultUnit  The contextual unit (usually {@code SI.METRE} or {@code SI.RADIAN}), or {@code null} if unknown.
-     * @param  mandatory    {@code true} if the axis is mandatory, or {@code false} if it is optional.
      * @return The {@code "AXIS"} element as a {@link CoordinateSystemAxis} object, or {@code null}
      *         if the axis was not required and there is no axis object.
      * @throws ParseException if the {@code "AXIS"} element can not be parsed.
      */
-    private CoordinateSystemAxis parseAxis(final Element parent, final boolean isGeographic,
-            final Unit<?> defaultUnit, final boolean mandatory) throws ParseException
+    private CoordinateSystemAxis parseAxis(final int mode, final Element parent, final boolean isGeographic,
+            final Unit<?> defaultUnit) throws ParseException
     {
-        final Element element;
-        if (mandatory) {
-            element = parent.pullElement(WKTKeywords.Axis);
-        } else {
-            element = parent.pullOptionalElement(WKTKeywords.Axis);
-            if (element == null) {
-                return null;
-            }
+        final Element element = parent.pullElement(mode, WKTKeywords.Axis);
+        if (element == null) {
+            return null;
         }
         String name = CharSequences.trimWhitespaces(element.pullString("name"));
         if (isGeographic) {
@@ -625,7 +615,7 @@ final class GeodeticObjectParser extends
             }
             unit = defaultUnit;
         }
-        final AxisDirection direction = Types.forCodeName(AxisDirection.class, orientation.keyword, mandatory);
+        final AxisDirection direction = Types.forCodeName(AxisDirection.class, orientation.keyword, mode == MANDATORY);
         /*
          * According ISO 19162, the abbreviation should be inserted between parenthesis in the name.
          * Example: "Easting (E)", "Longitude (L)". If we do not find an abbreviation, then we will
@@ -676,18 +666,24 @@ final class GeodeticObjectParser extends
      *     PRIMEM["<name>", <longitude> {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @param  angularUnit The contextual unit.
      * @return The {@code "PRIMEM"} element as a {@link PrimeMeridian} object.
      * @throws ParseException if the {@code "PRIMEM"} element can not be parsed.
      */
-    private PrimeMeridian parsePrimem(final Element parent, Unit<Angle> angularUnit) throws ParseException {
+    private PrimeMeridian parsePrimeMeridian(final int mode, final Element parent, Unit<Angle> angularUnit)
+            throws ParseException
+    {
         if (convention.usesCommonUnits) {
             angularUnit = NonSI.DEGREE_ANGLE;
         }
-        final Element element   = parent.pullElement(WKTKeywords.PrimeM);
-        final String  name      = element.pullString("name");
-        final double  longitude = element.pullDouble("longitude");
+        final Element element = parent.pullElement(mode, WKTKeywords.PrimeMeridian, WKTKeywords.PrimeM);
+        if (element == null) {
+            return null;
+        }
+        final String name      = element.pullString("name");
+        final double longitude = element.pullDouble("longitude");
         if (angularUnit == null) {
             throw element.missingComponent(WKTKeywords.AngleUnit);
         }
@@ -706,20 +702,21 @@ final class GeodeticObjectParser extends
      *     TOWGS84[<dx>, <dy>, <dz>, <ex>, <ey>, <ez>, <ppm>]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "TOWGS84"} element as a {@link org.apache.sis.referencing.datum.BursaWolfParameters} object,
      *         or {@code null} if no {@code "TOWGS84"} has been found.
      * @throws ParseException if the {@code "TOWGS84"} can not be parsed.
      */
-    private Object parseToWGS84(final Element parent) throws ParseException {
-        final Element element = parent.pullOptionalElement(WKTKeywords.ToWGS84);
+    private Object parseToWGS84(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.ToWGS84);
         if (element == null) {
             return null;
         }
         final double[] values = new double[ToWGS84.length];
         for (int i=0; i<values.length;) {
             values[i] = element.pullDouble(ToWGS84[i]);
-            if ((++i % 3) == 0 && element.peek() == null) {
+            if ((++i % 3) == 0 && element.isEmpty()) {
                 break;  // It is legal to have only 3 or 6 elements.
             }
         }
@@ -734,12 +731,16 @@ final class GeodeticObjectParser extends
      *     SPHEROID["<name>", <semi-major axis>, <inverse flattening> {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "SPHEROID"} element as an {@link Ellipsoid} object.
      * @throws ParseException if the {@code "SPHEROID"} element can not be parsed.
      */
-    private Ellipsoid parseSpheroid(final Element parent) throws ParseException {
-        final Element element      = parent.pullElement(WKTKeywords.Spheroid);
+    private Ellipsoid parseEllipsoid(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.Ellipsoid, WKTKeywords.Spheroid);
+        if (element == null) {
+            return null;
+        }
         final String name          = element.pullString("name");
         final double semiMajorAxis = element.pullDouble("semiMajorAxis");
         double inverseFlattening   = element.pullDouble("inverseFlattening");
@@ -761,18 +762,20 @@ final class GeodeticObjectParser extends
      *     PROJECTION["<name>" {,<authority>}]
      * }
      *
+     * @param  mode        {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent      The parent element.
      * @param  linearUnit  The linear unit of the parent {@code PROJCS} element, or {@code null}.
      * @param  angularUnit The angular unit of the parent {@code GEOCS} element, or {@code null}.
      * @return The {@code "PROJECTION"} element as a defining conversion.
      * @throws ParseException if the {@code "PROJECTION"} element can not be parsed.
      */
-    private Conversion parseProjection(final Element      parent,
-                                       final Unit<Length> linearUnit,
-                                       final Unit<Angle>  angularUnit)
-            throws ParseException
+    private Conversion parseProjection(final int mode, final Element parent,
+            final Unit<Length> linearUnit, final Unit<Angle> angularUnit) throws ParseException
     {
-        final Element element = parent.pullElement(WKTKeywords.Projection);
+        final Element element = parent.pullElement(mode, WKTKeywords.Projection);
+        if (element == null) {
+            return null;
+        }
         final String classification = element.pullString("name");
         /*
          * Set the list of parameters. NOTE: Parameters are defined in the parent
@@ -795,17 +798,24 @@ final class GeodeticObjectParser extends
      *     DATUM["<name>", <spheroid> {,<to wgs84>} {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
-     * @param  meridian the prime meridian.
+     * @param  meridian the prime meridian, or {@code null} for Greenwich.
      * @return The {@code "DATUM"} element as a {@link GeodeticDatum} object.
      * @throws ParseException if the {@code "DATUM"} element can not be parsed.
      */
-    private GeodeticDatum parseDatum(final Element parent, final PrimeMeridian meridian) throws ParseException {
-        final Element             element    = parent.pullElement(WKTKeywords.Datum);
-        final String              name       = element.pullString("name");
-        final Ellipsoid           ellipsoid  = parseSpheroid(element);
-        final Object              toWGS84    = parseToWGS84(element);     // Optional; may be null.
-        final Map<String,Object>  properties = parseMetadataAndClose(element, name);
+    private GeodeticDatum parseDatum(final int mode, final Element parent, PrimeMeridian meridian) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.Datum);
+        if (element == null) {
+            return null;
+        }
+        final String             name       = element.pullString("name");
+        final Ellipsoid          ellipsoid  = parseEllipsoid(MANDATORY, element);
+        final Object             toWGS84    = parseToWGS84(OPTIONAL, element);
+        final Map<String,Object> properties = parseMetadataAndClose(element, name);
+        if (meridian == null) {
+            meridian = referencing.getGreenwich();
+        }
         if (toWGS84 != null) {
             properties.put(ReferencingServices.BURSA_WOLF_KEY, toWGS84);
         }
@@ -823,14 +833,18 @@ final class GeodeticObjectParser extends
      *     VERT_DATUM["<name>", <datum type> {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "VERT_DATUM"} element as a {@link VerticalDatum} object.
      * @throws ParseException if the {@code "VERT_DATUM"} element can not be parsed.
      */
-    private VerticalDatum parseVertDatum(final Element parent) throws ParseException {
-        final Element element = parent.pullElement(WKTKeywords.Vert_Datum);
-        final String  name    = element.pullString ("name");
-        final int     datum   = element.pullInteger("datum");
+    private VerticalDatum parseVerticalDatum(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.VerticalDatum, WKTKeywords.Vert_Datum);
+        if (element == null) {
+            return null;
+        }
+        final String  name  = element.pullString ("name");
+        final int     datum = element.pullInteger("datum");
         final VerticalDatumType type = VerticalDatumTypes.fromLegacy(datum);
         // TODO: need to find a default value if null.
         try {
@@ -847,15 +861,19 @@ final class GeodeticObjectParser extends
      *     TimeDatum["<name>", TimeOrigin[<time origin>] {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "TimeDatum"} element as a {@link TemporalDatum} object.
      * @throws ParseException if the {@code "TimeDatum"} element can not be parsed.
      */
-    private TemporalDatum parseTimeDatum(final Element parent) throws ParseException {
-        final Element element = parent.pullElement(WKTKeywords.TimeDatum);
-        final String  name    = element.pullString ("name");
-        final Element origin  = element.pullElement(WKTKeywords.TimeOrigin);
-        final Date    epoch   = origin .pullDate("origin");
+    private TemporalDatum parseTimeDatum(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.TimeDatum);
+        if (element == null) {
+            return null;
+        }
+        final String  name   = element.pullString ("name");
+        final Element origin = element.pullElement(MANDATORY, WKTKeywords.TimeOrigin);
+        final Date    epoch  = origin .pullDate("origin");
         origin.close(ignoredElements);
         try {
             return datumFactory.createTemporalDatum(parseMetadataAndClose(element, name), epoch);
@@ -871,16 +889,20 @@ final class GeodeticObjectParser extends
      *     LOCAL_DATUM["<name>", <datum type> {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "LOCAL_DATUM"} element as an {@link EngineeringDatum} object.
      * @throws ParseException if the {@code "LOCAL_DATUM"} element can not be parsed.
      *
      * @todo The vertical datum type is currently ignored.
      */
-    private EngineeringDatum parseLocalDatum(final Element parent) throws ParseException {
-        final Element element = parent.pullElement(WKTKeywords.Local_Datum);
-        final String  name    = element.pullString ("name");
-        final int     datum   = element.pullInteger("datum");   // Ignored for now.
+    private EngineeringDatum parseEngineeringDatum(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.EngineeringDatum, WKTKeywords.Local_Datum);
+        if (element == null) {
+            return null;
+        }
+        final String name  = element.pullString ("name");
+        final int    datum = element.pullInteger("datum");   // Ignored for now.
         try {
             return datumFactory.createEngineeringDatum(parseMetadataAndClose(element, name));
         } catch (FactoryException exception) {
@@ -896,6 +918,7 @@ final class GeodeticObjectParser extends
      *     LOCAL_CS["<name>", <local datum>, <unit>, <axis>, {,<axis>}* {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "LOCAL_CS"} element as an {@link EngineeringCRS} object.
      * @throws ParseException if the {@code "LOCAL_CS"} element can not be parsed.
@@ -904,16 +927,19 @@ final class GeodeticObjectParser extends
      *       know which method to invokes in the {@link CSFactory} (is it a Cartesian
      *       coordinate system? a spherical one? etc.).
      */
-    private EngineeringCRS parseLocalCS(final Element parent) throws ParseException {
-        final Element          element    = parent.pullElement(WKTKeywords.Local_CS);
+    private EngineeringCRS parseEngineeringCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.EngineeringCRS, WKTKeywords.Local_CS);
+        if (element == null) {
+            return null;
+        }
         final String           name       = element.pullString("name");
-        final EngineeringDatum datum      = parseLocalDatum(element);
+        final EngineeringDatum datum      = parseEngineeringDatum(MANDATORY, element);
         final Unit<Length>     linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
-        CoordinateSystemAxis   axis       = parseAxis(element, false, linearUnit, true);
+        CoordinateSystemAxis   axis       = parseAxis(MANDATORY, element, false, linearUnit);
         final List<CoordinateSystemAxis> list = new ArrayList<>();
         do {
             list.add(axis);
-            axis = parseAxis(element, false, linearUnit, false);
+            axis = parseAxis(OPTIONAL, element, false, linearUnit);
         } while (axis != null);
         final CoordinateSystem cs = referencing.createAbstractCS(list.toArray(new CoordinateSystemAxis[list.size()]));
         try {
@@ -932,23 +958,27 @@ final class GeodeticObjectParser extends
      *            {,<axis> ,<axis> ,<axis>} {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "GEOCCS"} element as a {@link GeocentricCRS} object.
      * @throws ParseException if the {@code "GEOCCS"} element can not be parsed.
      */
-    private GeocentricCRS parseGeoCCS(final Element parent) throws ParseException {
-        final Element       element    = parent.pullElement(WKTKeywords.GeocCS);
+    private GeocentricCRS parseGeocentricCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.GeocCS);
+        if (element == null) {
+            return null;
+        }
         final String        name       = element.pullString("name");
-        final PrimeMeridian meridian   = parsePrimem(element, NonSI.DEGREE_ANGLE);
-        final GeodeticDatum datum      = parseDatum (element, meridian);
+        final PrimeMeridian meridian   = parsePrimeMeridian(MANDATORY, element, NonSI.DEGREE_ANGLE);
+        final GeodeticDatum datum      = parseDatum (MANDATORY, element, meridian);
         final Unit<Length>  linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
         CartesianCS cs;
         CoordinateSystemAxis axis0, axis1 = null, axis2 = null;
-        axis0 = parseAxis(element, false, linearUnit, false);
+        axis0 = parseAxis(OPTIONAL, element, false, linearUnit);
         try {
             if (axis0 != null) {
-                axis1 = parseAxis(element, false, linearUnit, true);
-                axis2 = parseAxis(element, false, linearUnit, true);
+                axis1 = parseAxis(MANDATORY, element, false, linearUnit);
+                axis2 = parseAxis(MANDATORY, element, false, linearUnit);
             }
             final Map<String,?> properties = parseMetadataAndClose(element, name);
             if (!isAxisIgnored(axis0)) {
@@ -974,16 +1004,20 @@ final class GeodeticObjectParser extends
      *     VERT_CS["<name>", <vert datum>, <linear unit>, {<axis>,} {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "VERT_CS"} element as a {@link VerticalCRS} object.
      * @throws ParseException if the {@code "VERT_CS"} element can not be parsed.
      */
-    private VerticalCRS parseVertCS(final Element parent) throws ParseException {
-        final Element        element    = parent.pullElement(WKTKeywords.Vert_CS);
+    private VerticalCRS parseVerticalCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.VerticalCRS, WKTKeywords.Vert_CS);
+        if (element == null) {
+            return null;
+        }
         final String         name       = element.pullString("name");
-        final VerticalDatum  datum      = parseVertDatum(element);
+        final VerticalDatum  datum      = parseVerticalDatum(MANDATORY, element);
         final Unit<Length>   linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
-        CoordinateSystemAxis axis       = parseAxis(element, false, linearUnit, false);
+        CoordinateSystemAxis axis       = parseAxis(OPTIONAL, element, false, linearUnit);
         try {
             if (isAxisIgnored(axis)) {
                 if (linearUnit == null) {
@@ -1022,16 +1056,20 @@ final class GeodeticObjectParser extends
     /**
      * Parses an <strong>optional</strong> {@code "TIMECRS"} element.
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "TIMECRS"} element as a {@link TemporalCRS} object.
      * @throws ParseException if the {@code "TIMECRS"} element can not be parsed.
      */
-    private TemporalCRS parseTimeCRS(final Element parent) throws ParseException {
-        final Element        element  = parent.pullElement(WKTKeywords.TimeCRS);
+    private TemporalCRS parseTimeCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.TimeCRS);
+        if (element == null) {
+            return null;
+        }
         final String         name     = element.pullString("name");
-        final TemporalDatum  datum    = parseTimeDatum(element);
+        final TemporalDatum  datum    = parseTimeDatum(MANDATORY, element);
         final Unit<Duration> timeUnit = parseDerivedUnit(element, WKTKeywords.TimeUnit, SI.SECOND);
-        CoordinateSystemAxis axis     = parseAxis(element, false, timeUnit, false);
+        CoordinateSystemAxis axis     = parseAxis(OPTIONAL, element, false, timeUnit);
         try {
             if (isAxisIgnored(axis)) {
                 if (timeUnit == null) {
@@ -1053,16 +1091,20 @@ final class GeodeticObjectParser extends
      *     GEOGCS["<name>", <datum>, <prime meridian>, <angular unit>  {,<twin axes>} {,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "GEOGCS"} element as a {@link GeographicCRS} object.
      * @throws ParseException if the {@code "GEOGCS"} element can not be parsed.
      */
-    private GeographicCRS parseGeoGCS(final Element parent) throws ParseException {
-        final Element       element     = parent.pullElement(WKTKeywords.GeogCS);
-              Object        name        = element.pullString("name");
+    private GeographicCRS parseGeographicCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.GeodeticCRS, WKTKeywords.GeodCRS, WKTKeywords.GeogCS);
+        if (element == null) {
+            return null;
+        }
+        Object              name        = element.pullString("name");
         final Unit<Angle>   angularUnit = parseDerivedUnit(element, WKTKeywords.AngleUnit, SI.RADIAN);
-        final PrimeMeridian meridian    = parsePrimem(element, angularUnit);
-        final GeodeticDatum datum       = parseDatum (element, meridian);
+        final PrimeMeridian meridian    = parsePrimeMeridian(MANDATORY, element, angularUnit);
+        final GeodeticDatum datum       = parseDatum(MANDATORY, element, meridian);
         if (((String) name).isEmpty()) {
             /*
              * GeographicCRS name is a mandatory property, but some invalid WKT with an empty string exist.
@@ -1071,11 +1113,11 @@ final class GeodeticObjectParser extends
              */
             name = datum.getName();
         }
-        CoordinateSystemAxis axis0 = parseAxis(element, true, angularUnit, false);
+        CoordinateSystemAxis axis0 = parseAxis(OPTIONAL, element, true, angularUnit);
         CoordinateSystemAxis axis1 = null;
         try {
             if (axis0 != null) {
-                axis1 = parseAxis(element, true, angularUnit, true);
+                axis1 = parseAxis(MANDATORY, element, true, angularUnit);
             }
             if (isAxisIgnored(axis0)) {
                 if (angularUnit == null) {
@@ -1101,24 +1143,28 @@ final class GeodeticObjectParser extends
      *            <linear unit> {,<twin axes>}{,<authority>}]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "PROJCS"} element as a {@link ProjectedCRS} object.
      * @throws ParseException if the {@code "GEOGCS"} element can not be parsed.
      */
-    private ProjectedCRS parseProjCS(final Element parent) throws ParseException {
-        final Element       element    = parent.pullElement(WKTKeywords.ProjCS);
+    private ProjectedCRS parseProjectedCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.ProjCS);
+        if (element == null) {
+            return null;
+        }
         final String        name       = element.pullString("name");
-        final GeographicCRS geoCRS     = parseGeoGCS(element);
+        final GeographicCRS geoCRS     = parseGeographicCRS(MANDATORY, element);
         final Unit<Length>  linearUnit = parseDerivedUnit(element, WKTKeywords.LengthUnit, SI.METRE);
         final boolean  usesCommonUnits = convention.usesCommonUnits;
-        final Conversion    conversion = parseProjection(element,
+        final Conversion    conversion = parseProjection(MANDATORY, element,
                 usesCommonUnits ? SI.METRE : linearUnit,
                 usesCommonUnits ? NonSI.DEGREE_ANGLE : geoCRS.getCoordinateSystem().getAxis(0).getUnit().asType(Angle.class));
-        CoordinateSystemAxis axis0 = parseAxis(element, false, linearUnit, false);
+        CoordinateSystemAxis axis0 = parseAxis(OPTIONAL, element, false, linearUnit);
         CoordinateSystemAxis axis1 = null;
         try {
             if (axis0 != null) {
-                axis1 = parseAxis(element, false, linearUnit, true);
+                axis1 = parseAxis(MANDATORY, element, false, linearUnit);
             }
             if (isAxisIgnored(axis0)) {
                 if (linearUnit == null) {
@@ -1143,15 +1189,19 @@ final class GeodeticObjectParser extends
      *     COMPD_CS["<name>", <head cs>, <tail cs> {,<authority>}]
      * }
      *
+     * @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.
      */
-    private CompoundCRS parseCompdCS(final Element parent) throws ParseException {
-        final List<CoordinateReferenceSystem> components = new ArrayList<>(4);
-        final Element element = parent.pullElement(WKTKeywords.Compd_CS);
-        final String  name    = element.pullString("name");
+    private CompoundCRS parseCompoundCRS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.CompoundCRS, WKTKeywords.Compd_CS);
+        if (element == null) {
+            return null;
+        }
+        final String  name = element.pullString("name");
         CoordinateReferenceSystem crs;
+        final List<CoordinateReferenceSystem> components = new ArrayList<>(4);
         while ((crs = parseCoordinateReferenceSystem(element, components.size() < 2)) != null) {
             components.add(crs);
         }
@@ -1171,12 +1221,16 @@ final class GeodeticObjectParser extends
      *     FITTED_CS["<name>", <to base>, <base cs>]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "FITTED_CS"} element as a {@link CompoundCRS} object.
      * @throws ParseException if the {@code "COMPD_CS"} element can not be parsed.
      */
-    private DerivedCRS parseFittedCS(final Element parent) throws ParseException {
-        final Element                   element = parent.pullElement(WKTKeywords.Fitted_CS);
+    private DerivedCRS parseFittedCS(final int mode, final Element parent) throws ParseException {
+        final Element element = parent.pullElement(mode, WKTKeywords.Fitted_CS);
+        if (element == null) {
+            return null;
+        }
         final String                    name    = element.pullString("name");
         final MathTransform             toBase  = parseMathTransform(element, true);
         final OperationMethod           method  = getOperationMethod();

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java?rev=1686050&r1=1686049&r2=1686050&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java [UTF-8] Wed Jun 17 15:10:56 2015
@@ -139,21 +139,17 @@ class MathTransformParser extends Abstra
     final MathTransform parseMathTransform(final Element element, final boolean mandatory) throws ParseException {
         lastMethod = null;
         classification = null;
-        String keyword = null;
-        final Object child = element.peek();
-        if (child instanceof Element) {
-            keyword = ((Element) child).keyword;
-            if (keyword != null) {
-                if (keyword.equalsIgnoreCase(WKTKeywords.Param_MT))       return parseParamMT      (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Concat_MT))      return parseConcatMT     (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.Inverse_MT))     return parseInverseMT    (element);
-                if (keyword.equalsIgnoreCase(WKTKeywords.PassThrough_MT)) return parsePassThroughMT(element);
+        MathTransform tr;
+        if ((tr = parseParamMT       (element)) == null &&
+            (tr = parseConcatMT      (element)) == null &&
+            (tr = parseInverseMT     (element)) == null &&
+            (tr = parsePassThroughMT (element)) == null)
+        {
+            if (mandatory) {
+                throw element.missingOrUnknownComponent(WKTKeywords.Param_MT);
             }
         }
-        if (mandatory) {
-            throw element.keywordNotFound(keyword);
-        }
-        return null;
+        return tr;
     }
 
     /**
@@ -170,7 +166,7 @@ class MathTransformParser extends Abstra
     {
         Element param = element;
         try {
-            while ((param = element.pullOptionalElement(WKTKeywords.Parameter)) != null) {
+            while ((param = element.pullElement(OPTIONAL, WKTKeywords.Parameter)) != null) {
                 final String                 name       = param.pullString("name");
                 final ParameterValue<?>      parameter  = parameters.parameter(name);
                 final ParameterDescriptor<?> descriptor = parameter.getDescriptor();
@@ -213,8 +209,11 @@ class MathTransformParser extends Abstra
      * @return The {@code "PARAM_MT"} element as an {@link MathTransform} object.
      * @throws ParseException if the {@code "PARAM_MT"} element can not be parsed.
      */
-    final MathTransform parseParamMT(final Element parent) throws ParseException {
-        final Element element = parent.pullElement(WKTKeywords.Param_MT);
+    private MathTransform parseParamMT(final Element parent) throws ParseException {
+        final Element element = parent.pullElement(FIRST, WKTKeywords.Param_MT);
+        if (element == null) {
+            return null;
+        }
         classification = element.pullString("classification");
         final ParameterValueGroup parameters;
         try {
@@ -252,8 +251,11 @@ class MathTransformParser extends Abstra
      * @return The {@code "INVERSE_MT"} element as an {@link MathTransform} object.
      * @throws ParseException if the {@code "INVERSE_MT"} element can not be parsed.
      */
-    final MathTransform parseInverseMT(final Element parent) throws ParseException {
-        final Element element = parent.pullElement(WKTKeywords.Inverse_MT);
+    private MathTransform parseInverseMT(final Element parent) throws ParseException {
+        final Element element = parent.pullElement(FIRST, WKTKeywords.Inverse_MT);
+        if (element == null) {
+            return null;
+        }
         MathTransform transform = parseMathTransform(element, true);
         try {
             transform = transform.inverse();
@@ -275,8 +277,11 @@ class MathTransformParser extends Abstra
      * @return The {@code "PASSTHROUGH_MT"} element as an {@link MathTransform} object.
      * @throws ParseException if the {@code "PASSTHROUGH_MT"} element can not be parsed.
      */
-    final MathTransform parsePassThroughMT(final Element parent) throws ParseException {
-        final Element element           = parent.pullElement(WKTKeywords.PassThrough_MT);
+    private MathTransform parsePassThroughMT(final Element parent) throws ParseException {
+        final Element element = parent.pullElement(FIRST, WKTKeywords.PassThrough_MT);
+        if (element == null) {
+            return null;
+        }
         final int firstAffectedOrdinate = parent.pullInteger("firstAffectedOrdinate");
         final MathTransform transform   = parseMathTransform(element, true);
         element.close(ignoredElements);
@@ -294,12 +299,16 @@ class MathTransformParser extends Abstra
      *     CONCAT_MT[<math transform> {,<math transform>}*]
      * }
      *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
      * @param  parent The parent element.
      * @return The {@code "CONCAT_MT"} element as an {@link MathTransform} object.
      * @throws ParseException if the {@code "CONCAT_MT"} element can not be parsed.
      */
-    final MathTransform parseConcatMT(final Element parent) throws ParseException {
-        final Element element = parent.pullElement(WKTKeywords.Concat_MT);
+    private MathTransform parseConcatMT(final Element parent) throws ParseException {
+        final Element element = parent.pullElement(FIRST, WKTKeywords.Concat_MT);
+        if (element == null) {
+            return null;
+        }
         MathTransform transform = parseMathTransform(element, true);
         MathTransform optionalTransform;
         while ((optionalTransform = parseMathTransform(element, false)) != null) {

Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java?rev=1686050&r1=1686049&r2=1686050&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java [UTF-8] Wed Jun 17 15:10:56 2015
@@ -223,7 +223,7 @@ public final strictfp class ElementTest
         Element element = parse("TimeDatum[“Modified Julian”, TimeOrigin[1858-11-17T00:00:00.0Z]]");
         assertEquals("keyword", "TimeDatum", element.keyword);
         assertEquals("name", "Modified Julian", element.pullString("name"));
-        Element inner = element.pullElement("TimeOrigin");
+        Element inner = element.pullElement(AbstractParser.MANDATORY, "TimeOrigin");
         assertEquals("keyword", "TimeOrigin", inner.keyword);
         assertEquals("date", TestUtilities.date("1858-11-17 00:00:00"), inner.pullDate("date"));
         inner.close(null);



Mime
View raw message