1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.yaml.snakeyaml.serializer;
18
19 import java.io.IOException;
20 import java.text.NumberFormat;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.yaml.snakeyaml.DumperOptions;
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 Integer[] useVersion;
57 private Map<String, String> useTags;
58 private Set<Node> serializedNodes;
59 private Map<Node, String> anchors;
60 private int lastAnchorId;
61 private Boolean closed;
62 private Tag explicitRoot;
63
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().getArray();
71 }
72 this.useTags = opts.getTags();
73 this.serializedNodes = new HashSet<Node>();
74 this.anchors = new HashMap<Node, String>();
75 this.lastAnchorId = 0;
76 this.closed = null;
77 this.explicitRoot = rootTag;
78 }
79
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
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
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, null);
113 this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd));
114 this.serializedNodes.clear();
115 this.anchors.clear();
116 this.lastAnchorId = 0;
117 }
118
119 private void anchorNode(Node node) {
120 if (node.getNodeId() == NodeId.anchor) {
121 node = ((AnchorNode) node).getRealNode();
122 }
123 if (this.anchors.containsKey(node)) {
124 String anchor = this.anchors.get(node);
125 if (null == anchor) {
126 anchor = generateAnchor();
127 this.anchors.put(node, anchor);
128 }
129 } else {
130 this.anchors.put(node, null);
131 switch (node.getNodeId()) {
132 case sequence:
133 SequenceNode seqNode = (SequenceNode) node;
134 List<Node> list = seqNode.getValue();
135 for (Node item : list) {
136 anchorNode(item);
137 }
138 break;
139 case mapping:
140 MappingNode mnode = (MappingNode) node;
141 List<NodeTuple> map = mnode.getValue();
142 for (NodeTuple object : map) {
143 Node key = object.getKeyNode();
144 Node value = object.getValueNode();
145 anchorNode(key);
146 anchorNode(value);
147 }
148 break;
149 }
150 }
151 }
152
153 private String generateAnchor() {
154 this.lastAnchorId++;
155 NumberFormat format = NumberFormat.getNumberInstance();
156 format.setMinimumIntegerDigits(3);
157 format.setGroupingUsed(false);
158 String anchorId = format.format(this.lastAnchorId);
159 return "id" + anchorId;
160 }
161
162 private void serializeNode(Node node, Node parent, Object index) throws IOException {
163 if (node.getNodeId() == NodeId.anchor) {
164 node = ((AnchorNode) node).getRealNode();
165 }
166 String tAlias = this.anchors.get(node);
167 if (this.serializedNodes.contains(node)) {
168 this.emitter.emit(new AliasEvent(tAlias, null, null));
169 } else {
170 this.serializedNodes.add(node);
171 switch (node.getNodeId()) {
172 case scalar:
173 ScalarNode scalarNode = (ScalarNode) node;
174 Tag detectedTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), true);
175 Tag defaultTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), false);
176 ImplicitTuple tuple = new ImplicitTuple(node.getTag().equals(detectedTag), node
177 .getTag().equals(defaultTag));
178 ScalarEvent event = new ScalarEvent(tAlias, node.getTag().getValue(), tuple,
179 scalarNode.getValue(), null, null, scalarNode.getStyle());
180 this.emitter.emit(event);
181 break;
182 case sequence:
183 SequenceNode seqNode = (SequenceNode) node;
184 boolean implicitS = (node.getTag().equals(this.resolver.resolve(NodeId.sequence,
185 null, true)));
186 this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag().getValue(),
187 implicitS, null, null, seqNode.getFlowStyle()));
188 int indexCounter = 0;
189 List<Node> list = seqNode.getValue();
190 for (Node item : list) {
191 serializeNode(item, node, indexCounter);
192 indexCounter++;
193 }
194 this.emitter.emit(new SequenceEndEvent(null, null));
195 break;
196 default:
197 Tag implicitTag = this.resolver.resolve(NodeId.mapping, null, true);
198 boolean implicitM = (node.getTag().equals(implicitTag));
199 this.emitter.emit(new MappingStartEvent(tAlias, node.getTag().getValue(),
200 implicitM, null, null, ((CollectionNode) node).getFlowStyle()));
201 MappingNode mnode = (MappingNode) node;
202 List<NodeTuple> map = mnode.getValue();
203 for (NodeTuple row : map) {
204 Node key = row.getKeyNode();
205 Node value = row.getValueNode();
206 serializeNode(key, mnode, null);
207 serializeNode(value, mnode, key);
208 }
209 this.emitter.emit(new MappingEndEvent(null, null));
210 }
211 }
212 }
213 }