blob: 528133e77ae68013e3e263ebdfbb7346e3a87f14 [file] [log] [blame]
/**
* Copyright (c) 2008-2009 Andrey Somov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.yaml.snakeyaml.composer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.yaml.snakeyaml.events.AliasEvent;
import org.yaml.snakeyaml.events.Event;
import org.yaml.snakeyaml.events.MappingEndEvent;
import org.yaml.snakeyaml.events.MappingStartEvent;
import org.yaml.snakeyaml.events.NodeEvent;
import org.yaml.snakeyaml.events.ScalarEvent;
import org.yaml.snakeyaml.events.SequenceEndEvent;
import org.yaml.snakeyaml.events.SequenceStartEvent;
import org.yaml.snakeyaml.events.StreamEndEvent;
import org.yaml.snakeyaml.events.StreamStartEvent;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeId;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.SequenceNode;
import org.yaml.snakeyaml.parser.Parser;
import org.yaml.snakeyaml.resolver.Resolver;
/**
* @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
*/
public class Composer {
private final Parser parser;
private final Resolver resolver;
private final Map<String, Node> anchors;
private final Set<Node> recursiveNodes;
public Composer(Parser parser, Resolver resolver) {
this.parser = parser;
this.resolver = resolver;
this.anchors = new HashMap<String, Node>();
this.recursiveNodes = new HashSet<Node>();
}
public boolean checkNode() {
// Drop the STREAM-START event.
if (parser.checkEvent(StreamStartEvent.class)) {
parser.getEvent();
}
// If there are more documents available?
return !parser.checkEvent(StreamEndEvent.class);
}
public Node getNode() {
// Get the root node of the next document.
if (!parser.checkEvent(StreamEndEvent.class)) {
return composeDocument();
} else {
return (Node) null;
}
}
public Node getSingleNode() {
// Drop the STREAM-START event.
parser.getEvent();
// Compose a document if the stream is not empty.
Node document = null;
if (!parser.checkEvent(StreamEndEvent.class)) {
document = composeDocument();
}
// Ensure that the stream contains no more documents.
if (!parser.checkEvent(StreamEndEvent.class)) {
Event event = parser.getEvent();
throw new ComposerException("expected a single document in the stream", document
.getStartMark(), "but found another document", event.getStartMark());
}
// Drop the STREAM-END event.
parser.getEvent();
return document;
}
private Node composeDocument() {
// Drop the DOCUMENT-START event.
parser.getEvent();
// Compose the root node.
Node node = composeNode(null, null);
// Drop the DOCUMENT-END event.
parser.getEvent();
this.anchors.clear();
recursiveNodes.clear();
return node;
}
private Node composeNode(Node parent, Object index) {
recursiveNodes.add(parent);
if (parser.checkEvent(AliasEvent.class)) {
AliasEvent event = (AliasEvent) parser.getEvent();
String anchor = event.getAnchor();
if (!anchors.containsKey(anchor)) {
throw new ComposerException(null, null, "found undefined alias " + anchor, event
.getStartMark());
}
Node result = (Node) anchors.get(anchor);
if (recursiveNodes.remove(result)) {
result.setTwoStepsConstruction(true);
}
return result;
}
NodeEvent event = (NodeEvent) parser.peekEvent();
String anchor = null;
anchor = event.getAnchor();
if (anchor != null && anchors.containsKey(anchor)) {
throw new ComposerException("found duplicate anchor " + anchor + "; first occurence",
this.anchors.get(anchor).getStartMark(), "second occurence", event
.getStartMark());
}
// resolver.descendResolver(parent, index);
Node node = null;
if (parser.checkEvent(ScalarEvent.class)) {
node = composeScalarNode(anchor);
} else if (parser.checkEvent(SequenceStartEvent.class)) {
node = composeSequenceNode(anchor);
} else {
node = composeMappingNode(anchor);
}
// resolver.ascendResolver();
recursiveNodes.remove(parent);
return node;
}
private Node composeScalarNode(String anchor) {
ScalarEvent ev = (ScalarEvent) parser.getEvent();
String tag = ev.getTag();
boolean resolved = false;
if (tag == null || tag.equals("!")) {
tag = resolver.resolve(NodeId.scalar, ev.getValue(), ev.getImplicit().isFirst());
resolved = true;
}
Node node = new ScalarNode(tag, resolved, ev.getValue(), ev.getStartMark(),
ev.getEndMark(), ev.getStyle());
if (anchor != null) {
anchors.put(anchor, node);
}
return node;
}
private Node composeSequenceNode(String anchor) {
SequenceStartEvent startEvent = (SequenceStartEvent) parser.getEvent();
String tag = startEvent.getTag();
boolean resolved = false;
if (tag == null || tag.equals("!")) {
tag = resolver.resolve(NodeId.sequence, null, startEvent.getImplicit());
resolved = true;
}
SequenceNode node = new SequenceNode(tag, resolved, new ArrayList<Node>(), startEvent
.getStartMark(), null, startEvent.getFlowStyle());
if (anchor != null) {
anchors.put(anchor, node);
}
int index = 0;
while (!parser.checkEvent(SequenceEndEvent.class)) {
(node.getValue()).add(composeNode(node, new Integer(index)));
index++;
}
Event endEvent = parser.getEvent();
node.setEndMark(endEvent.getEndMark());
return node;
}
private Node composeMappingNode(String anchor) {
MappingStartEvent startEvent = (MappingStartEvent) parser.getEvent();
String tag = startEvent.getTag();
boolean resolved = false;
if (tag == null || tag.equals("!")) {
tag = resolver.resolve(NodeId.mapping, null, startEvent.getImplicit());
resolved = true;
}
MappingNode node = new MappingNode(tag, resolved, new ArrayList<NodeTuple>(), startEvent
.getStartMark(), null, startEvent.getFlowStyle());
if (anchor != null) {
anchors.put(anchor, node);
}
while (!parser.checkEvent(MappingEndEvent.class)) {
Node itemKey = composeNode(node, null);
Node itemValue = composeNode(node, itemKey);
node.getValue().add(new NodeTuple(itemKey, itemValue));
}
Event endEvent = parser.getEvent();
node.setEndMark(endEvent.getEndMark());
return node;
}
}