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 }