1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.yaml.snakeyaml.composer;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.yaml.snakeyaml.events.AliasEvent;
27 import org.yaml.snakeyaml.events.Event;
28 import org.yaml.snakeyaml.events.MappingStartEvent;
29 import org.yaml.snakeyaml.events.NodeEvent;
30 import org.yaml.snakeyaml.events.ScalarEvent;
31 import org.yaml.snakeyaml.events.SequenceStartEvent;
32 import org.yaml.snakeyaml.nodes.MappingNode;
33 import org.yaml.snakeyaml.nodes.Node;
34 import org.yaml.snakeyaml.nodes.NodeId;
35 import org.yaml.snakeyaml.nodes.NodeTuple;
36 import org.yaml.snakeyaml.nodes.ScalarNode;
37 import org.yaml.snakeyaml.nodes.SequenceNode;
38 import org.yaml.snakeyaml.nodes.Tag;
39 import org.yaml.snakeyaml.parser.Parser;
40 import org.yaml.snakeyaml.resolver.Resolver;
41
42
43
44
45
46
47
48
49 public class Composer {
50 private final Parser parser;
51 private final Resolver resolver;
52 private final Map<String, Node> anchors;
53 private final Set<Node> recursiveNodes;
54
55 public Composer(Parser parser, Resolver resolver) {
56 this.parser = parser;
57 this.resolver = resolver;
58 this.anchors = new HashMap<String, Node>();
59 this.recursiveNodes = new HashSet<Node>();
60 }
61
62
63
64
65
66
67 public boolean checkNode() {
68
69 if (parser.checkEvent(Event.ID.StreamStart)) {
70 parser.getEvent();
71 }
72
73 return !parser.checkEvent(Event.ID.StreamEnd);
74 }
75
76
77
78
79
80
81
82 public Node getNode() {
83
84 if (!parser.checkEvent(Event.ID.StreamEnd)) {
85 return composeDocument();
86 } else {
87 return null;
88 }
89 }
90
91
92
93
94
95
96
97
98
99
100 public Node getSingleNode() {
101
102 parser.getEvent();
103
104 Node document = null;
105 if (!parser.checkEvent(Event.ID.StreamEnd)) {
106 document = composeDocument();
107 }
108
109 if (!parser.checkEvent(Event.ID.StreamEnd)) {
110 Event event = parser.getEvent();
111 throw new ComposerException("expected a single document in the stream",
112 document.getStartMark(), "but found another document", event.getStartMark());
113 }
114
115 parser.getEvent();
116 return document;
117 }
118
119 private Node composeDocument() {
120
121 parser.getEvent();
122
123 Node node = composeNode(null, null);
124
125 parser.getEvent();
126 this.anchors.clear();
127 recursiveNodes.clear();
128 return node;
129 }
130
131 private Node composeNode(Node parent, Object index) {
132 recursiveNodes.add(parent);
133 if (parser.checkEvent(Event.ID.Alias)) {
134 AliasEvent event = (AliasEvent) parser.getEvent();
135 String anchor = event.getAnchor();
136 if (!anchors.containsKey(anchor)) {
137 throw new ComposerException(null, null, "found undefined alias " + anchor,
138 event.getStartMark());
139 }
140 Node result = anchors.get(anchor);
141 if (recursiveNodes.remove(result)) {
142 result.setTwoStepsConstruction(true);
143 }
144 return result;
145 }
146 NodeEvent event = (NodeEvent) parser.peekEvent();
147 String anchor = null;
148 anchor = event.getAnchor();
149 if (anchor != null && anchors.containsKey(anchor)) {
150 throw new ComposerException("found duplicate anchor " + anchor + "; first occurence",
151 this.anchors.get(anchor).getStartMark(), "second occurence",
152 event.getStartMark());
153 }
154 Node node = null;
155 if (parser.checkEvent(Event.ID.Scalar)) {
156 node = composeScalarNode(anchor);
157 } else if (parser.checkEvent(Event.ID.SequenceStart)) {
158 node = composeSequenceNode(anchor);
159 } else {
160 node = composeMappingNode(anchor);
161 }
162 recursiveNodes.remove(parent);
163 return node;
164 }
165
166 private Node composeScalarNode(String anchor) {
167 ScalarEvent ev = (ScalarEvent) parser.getEvent();
168 String tag = ev.getTag();
169 boolean resolved = false;
170 Tag nodeTag;
171 if (tag == null || tag.equals("!")) {
172 nodeTag = resolver.resolve(NodeId.scalar, ev.getValue(), ev.getImplicit().canOmitTagInPlainScalar());
173 resolved = true;
174 } else {
175 nodeTag = new Tag(tag);
176 }
177 Node node = new ScalarNode(nodeTag, resolved, ev.getValue(), ev.getStartMark(),
178 ev.getEndMark(), ev.getStyle());
179 if (anchor != null) {
180 anchors.put(anchor, node);
181 }
182 return node;
183 }
184
185 private Node composeSequenceNode(String anchor) {
186 SequenceStartEvent startEvent = (SequenceStartEvent) parser.getEvent();
187 String tag = startEvent.getTag();
188 Tag nodeTag;
189 boolean resolved = false;
190 if (tag == null || tag.equals("!")) {
191 nodeTag = resolver.resolve(NodeId.sequence, null, startEvent.getImplicit());
192 resolved = true;
193 } else {
194 nodeTag = new Tag(tag);
195 }
196 final ArrayList<Node> children = new ArrayList<Node>();
197 SequenceNode node = new SequenceNode(nodeTag, resolved, children,
198 startEvent.getStartMark(), null, startEvent.getFlowStyle());
199 if (anchor != null) {
200 anchors.put(anchor, node);
201 }
202 int index = 0;
203 while (!parser.checkEvent(Event.ID.SequenceEnd)) {
204 children.add(composeNode(node, index));
205 index++;
206 }
207 Event endEvent = parser.getEvent();
208 node.setEndMark(endEvent.getEndMark());
209 return node;
210 }
211
212 private Node composeMappingNode(String anchor) {
213 MappingStartEvent startEvent = (MappingStartEvent) parser.getEvent();
214 String tag = startEvent.getTag();
215 Tag nodeTag;
216 boolean resolved = false;
217 if (tag == null || tag.equals("!")) {
218 nodeTag = resolver.resolve(NodeId.mapping, null, startEvent.getImplicit());
219 resolved = true;
220 } else {
221 nodeTag = new Tag(tag);
222 }
223
224 final List<NodeTuple> children = new ArrayList<NodeTuple>();
225 MappingNode node = new MappingNode(nodeTag, resolved, children, startEvent.getStartMark(),
226 null, startEvent.getFlowStyle());
227 if (anchor != null) {
228 anchors.put(anchor, node);
229 }
230 while (!parser.checkEvent(Event.ID.MappingEnd)) {
231 Node itemKey = composeNode(node, null);
232 if (itemKey.getTag().equals(Tag.MERGE)) {
233 node.setMerged(true);
234 } else if (itemKey.getTag().equals(Tag.VALUE)) {
235 itemKey.setTag(Tag.STR);
236 }
237 Node itemValue = composeNode(node, itemKey);
238 children.add(new NodeTuple(itemKey, itemValue));
239 }
240 Event endEvent = parser.getEvent();
241 node.setEndMark(endEvent.getEndMark());
242 return node;
243 }
244 }