• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2008, 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 package org.yaml.snakeyaml.serializer;
17 
18 import java.io.IOException;
19 import java.text.NumberFormat;
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.DumperOptions;
27 import org.yaml.snakeyaml.DumperOptions.Version;
28 import org.yaml.snakeyaml.emitter.Emitable;
29 import org.yaml.snakeyaml.events.AliasEvent;
30 import org.yaml.snakeyaml.events.DocumentEndEvent;
31 import org.yaml.snakeyaml.events.DocumentStartEvent;
32 import org.yaml.snakeyaml.events.ImplicitTuple;
33 import org.yaml.snakeyaml.events.MappingEndEvent;
34 import org.yaml.snakeyaml.events.MappingStartEvent;
35 import org.yaml.snakeyaml.events.ScalarEvent;
36 import org.yaml.snakeyaml.events.SequenceEndEvent;
37 import org.yaml.snakeyaml.events.SequenceStartEvent;
38 import org.yaml.snakeyaml.events.StreamEndEvent;
39 import org.yaml.snakeyaml.events.StreamStartEvent;
40 import org.yaml.snakeyaml.nodes.AnchorNode;
41 import org.yaml.snakeyaml.nodes.CollectionNode;
42 import org.yaml.snakeyaml.nodes.MappingNode;
43 import org.yaml.snakeyaml.nodes.Node;
44 import org.yaml.snakeyaml.nodes.NodeId;
45 import org.yaml.snakeyaml.nodes.NodeTuple;
46 import org.yaml.snakeyaml.nodes.ScalarNode;
47 import org.yaml.snakeyaml.nodes.SequenceNode;
48 import org.yaml.snakeyaml.nodes.Tag;
49 import org.yaml.snakeyaml.resolver.Resolver;
50 
51 public final class Serializer {
52     private final Emitable emitter;
53     private final Resolver resolver;
54     private boolean explicitStart;
55     private boolean explicitEnd;
56     private Version useVersion;
57     private Map<String, String> useTags;
58     private Set<Node> serializedNodes;
59     private Map<Node, String> anchors;
60     private AnchorGenerator anchorGenerator;
61     private Boolean closed;
62     private Tag explicitRoot;
63 
Serializer(Emitable emitter, Resolver resolver, DumperOptions opts, Tag rootTag)64     public Serializer(Emitable emitter, Resolver resolver, DumperOptions opts, Tag rootTag) {
65         this.emitter = emitter;
66         this.resolver = resolver;
67         this.explicitStart = opts.isExplicitStart();
68         this.explicitEnd = opts.isExplicitEnd();
69         if (opts.getVersion() != null) {
70             this.useVersion = opts.getVersion();
71         }
72         this.useTags = opts.getTags();
73         this.serializedNodes = new HashSet<Node>();
74         this.anchors = new HashMap<Node, String>();
75         this.anchorGenerator = opts.getAnchorGenerator();
76         this.closed = null;
77         this.explicitRoot = rootTag;
78     }
79 
open()80     public void open() throws IOException {
81         if (closed == null) {
82             this.emitter.emit(new StreamStartEvent(null, null));
83             this.closed = Boolean.FALSE;
84         } else if (Boolean.TRUE.equals(closed)) {
85             throw new SerializerException("serializer is closed");
86         } else {
87             throw new SerializerException("serializer is already opened");
88         }
89     }
90 
close()91     public void close() throws IOException {
92         if (closed == null) {
93             throw new SerializerException("serializer is not opened");
94         } else if (!Boolean.TRUE.equals(closed)) {
95             this.emitter.emit(new StreamEndEvent(null, null));
96             this.closed = Boolean.TRUE;
97         }
98     }
99 
serialize(Node node)100     public void serialize(Node node) throws IOException {
101         if (closed == null) {
102             throw new SerializerException("serializer is not opened");
103         } else if (closed) {
104             throw new SerializerException("serializer is closed");
105         }
106         this.emitter.emit(new DocumentStartEvent(null, null, this.explicitStart, this.useVersion,
107                 useTags));
108         anchorNode(node);
109         if (explicitRoot != null) {
110             node.setTag(explicitRoot);
111         }
112         serializeNode(node, null);
113         this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd));
114         this.serializedNodes.clear();
115         this.anchors.clear();
116     }
117 
anchorNode(Node node)118     private void anchorNode(Node node) {
119         if (node.getNodeId() == NodeId.anchor) {
120             node = ((AnchorNode) node).getRealNode();
121         }
122         if (this.anchors.containsKey(node)) {
123             String anchor = this.anchors.get(node);
124             if (null == anchor) {
125                 anchor = this.anchorGenerator.nextAnchor(node);
126                 this.anchors.put(node, anchor);
127             }
128         } else {
129             this.anchors.put(node, null);
130             switch (node.getNodeId()) {
131             case sequence:
132                 SequenceNode seqNode = (SequenceNode) node;
133                 List<Node> list = seqNode.getValue();
134                 for (Node item : list) {
135                     anchorNode(item);
136                 }
137                 break;
138             case mapping:
139                 MappingNode mnode = (MappingNode) node;
140                 List<NodeTuple> map = mnode.getValue();
141                 for (NodeTuple object : map) {
142                     Node key = object.getKeyNode();
143                     Node value = object.getValueNode();
144                     anchorNode(key);
145                     anchorNode(value);
146                 }
147                 break;
148             }
149         }
150     }
151 
serializeNode(Node node, Node parent)152     private void serializeNode(Node node, Node parent) throws IOException {
153         if (node.getNodeId() == NodeId.anchor) {
154             node = ((AnchorNode) node).getRealNode();
155         }
156         String tAlias = this.anchors.get(node);
157         if (this.serializedNodes.contains(node)) {
158             this.emitter.emit(new AliasEvent(tAlias, null, null));
159         } else {
160             this.serializedNodes.add(node);
161             switch (node.getNodeId()) {
162             case scalar:
163                 ScalarNode scalarNode = (ScalarNode) node;
164                 Tag detectedTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), true);
165                 Tag defaultTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), false);
166                 ImplicitTuple tuple = new ImplicitTuple(node.getTag().equals(detectedTag), node
167                         .getTag().equals(defaultTag));
168                 ScalarEvent event = new ScalarEvent(tAlias, node.getTag().getValue(), tuple,
169                         scalarNode.getValue(), null, null, scalarNode.getStyle());
170                 this.emitter.emit(event);
171                 break;
172             case sequence:
173                 SequenceNode seqNode = (SequenceNode) node;
174                 boolean implicitS = node.getTag().equals(this.resolver.resolve(NodeId.sequence,
175                         null, true));
176                 this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag().getValue(),
177                         implicitS, null, null, seqNode.getFlowStyle()));
178                 List<Node> list = seqNode.getValue();
179                 for (Node item : list) {
180                     serializeNode(item, node);
181                 }
182                 this.emitter.emit(new SequenceEndEvent(null, null));
183                 break;
184             default:// instance of MappingNode
185                 Tag implicitTag = this.resolver.resolve(NodeId.mapping, null, true);
186                 boolean implicitM = node.getTag().equals(implicitTag);
187                 this.emitter.emit(new MappingStartEvent(tAlias, node.getTag().getValue(),
188                         implicitM, null, null, ((CollectionNode) node).getFlowStyle()));
189                 MappingNode mnode = (MappingNode) node;
190                 List<NodeTuple> map = mnode.getValue();
191                 for (NodeTuple row : map) {
192                     Node key = row.getKeyNode();
193                     Node value = row.getValueNode();
194                     serializeNode(key, mnode);
195                     serializeNode(value, mnode);
196                 }
197                 this.emitter.emit(new MappingEndEvent(null, null));
198             }
199         }
200     }
201 }
202