View Javadoc

    1   /**
    2    * Copyright (c) 2008-2011, http://www.snakeyaml.org
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package org.yaml.snakeyaml.resolver;
    18
    19  import java.util.ArrayList;
    20  import java.util.HashMap;
    21  import java.util.List;
    22  import java.util.Map;
    23  import java.util.regex.Pattern;
    24
    25  import org.yaml.snakeyaml.nodes.NodeId;
    26  import org.yaml.snakeyaml.nodes.Tag;
    27
    28  /**
    29   * Resolver tries to detect a type by scalars's content (when the type is
    30   * implicit)
    31   */
    32  public class Resolver {
    33      public static final Pattern BOOL = Pattern
    34              .compile("^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$");
    35
    36      /**
    37       * The regular expression is taken from the 1.2 specification but '_'s are
    38       * added to keep backwards compatibility
    39       */
    40      public static final Pattern FLOAT = Pattern
    41              .compile("^([-+]?(\\.[0-9]+|[0-9_]+(\\.[0-9_]*)?)([eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");
    42      public static final Pattern INT = Pattern
    43              .compile("^(?:[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[0-9a-fA-F_]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$");
    44      public static final Pattern MERGE = Pattern.compile("^(?:<<)$");
    45      public static final Pattern NULL = Pattern.compile("^(?:~|null|Null|NULL| )$");
    46      public static final Pattern EMPTY = Pattern.compile("^$");
    47      public static final Pattern TIMESTAMP = Pattern
    48              .compile("^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?(?:[Tt]|[ \t]+)[0-9][0-9]?:[0-9][0-9]:[0-9][0-9](?:\\.[0-9]*)?(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$");
    49      public static final Pattern VALUE = Pattern.compile("^(?:=)$");
    50      public static final Pattern YAML = Pattern.compile("^(?:!|&|\\*)$");
    51
    52      protected Map<Character, List<ResolverTuple>> yamlImplicitResolvers = new HashMap<Character, List<ResolverTuple>>();
    53
    54      /**
    55       * Create Resolver
    56       *
    57       * @param respectDefaultImplicitScalars
    58       *            false to parse/dump scalars as plain Strings
    59       * @deprecated override addImplicitResolvers instead
    60       */
    61      public Resolver(boolean respectDefaultImplicitScalars) {
    62          if (respectDefaultImplicitScalars) {
    63              addImplicitResolvers();
    64          }
    65      }
    66
    67      protected void addImplicitResolvers() {
    68          addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO");
    69          /*
    70           * INT must be before FLOAT because the regular expression for FLOAT
    71           * matches INT (see issue 130)
    72           * http://code.google.com/p/snakeyaml/issues/detail?id=130
    73           */
    74          addImplicitResolver(Tag.INT, INT, "-+0123456789");
    75          addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
    76          addImplicitResolver(Tag.MERGE, MERGE, "<");
    77          addImplicitResolver(Tag.NULL, NULL, "~nN\0");
    78          addImplicitResolver(Tag.NULL, EMPTY, null);
    79          addImplicitResolver(Tag.TIMESTAMP, TIMESTAMP, "0123456789");
    80          addImplicitResolver(Tag.VALUE, VALUE, "=");
    81          // The following implicit resolver is only for documentation
    82          // purposes.
    83          // It cannot work
    84          // because plain scalars cannot start with '!', '&', or '*'.
    85          addImplicitResolver(Tag.YAML, YAML, "!&*");
    86      }
    87
    88      public Resolver() {
    89          this(true);
    90      }
    91
    92      public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
    93          if (first == null) {
    94              List<ResolverTuple> curr = yamlImplicitResolvers.get(null);
    95              if (curr == null) {
    96                  curr = new ArrayList<ResolverTuple>();
    97                  yamlImplicitResolvers.put(null, curr);
    98              }
    99              curr.add(new ResolverTuple(tag, regexp));
    100         } else {
    101             char[] chrs = first.toCharArray();
    102             for (int i = 0, j = chrs.length; i < j; i++) {
    103                 Character theC = new Character(chrs[i]);
    104                 if (theC == 0) {
    105                     // special case: for null
    106                     theC = null;
    107                 }
    108                 List<ResolverTuple> curr = yamlImplicitResolvers.get(theC);
    109                 if (curr == null) {
    110                     curr = new ArrayList<ResolverTuple>();
    111                     yamlImplicitResolvers.put(theC, curr);
    112                 }
    113                 curr.add(new ResolverTuple(tag, regexp));
    114             }
    115         }
    116     }
    117
    118     public Tag resolve(NodeId kind, String value, boolean implicit) {
    119         if (kind == NodeId.scalar && implicit) {
    120             List<ResolverTuple> resolvers = null;
    121             if (value.length() == 0) {
    122                 resolvers = yamlImplicitResolvers.get('\0');
    123             } else {
    124                 resolvers = yamlImplicitResolvers.get(value.charAt(0));
    125             }
    126             if (resolvers != null) {
    127                 for (ResolverTuple v : resolvers) {
    128                     Tag tag = v.getTag();
    129                     Pattern regexp = v.getRegexp();
    130                     if (regexp.matcher(value).matches()) {
    131                         return tag;
    132                     }
    133                 }
    134             }
    135             if (yamlImplicitResolvers.containsKey(null)) {
    136                 for (ResolverTuple v : yamlImplicitResolvers.get(null)) {
    137                     Tag tag = v.getTag();
    138                     Pattern regexp = v.getRegexp();
    139                     if (regexp.matcher(value).matches()) {
    140                         return tag;
    141                     }
    142                 }
    143             }
    144         }
    145         switch (kind) {
    146         case scalar:
    147             return Tag.STR;
    148         case sequence:
    149             return Tag.SEQ;
    150         default:
    151             return Tag.MAP;
    152         }
    153     }
    154 }