1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
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 int lastAnchorId; |
61 | |
private Boolean closed; |
62 | |
private Tag explicitRoot; |
63 | |
|
64 | 81949 | public Serializer(Emitable emitter, Resolver resolver, DumperOptions opts, Tag rootTag) { |
65 | 81949 | this.emitter = emitter; |
66 | 81949 | this.resolver = resolver; |
67 | 81949 | this.explicitStart = opts.isExplicitStart(); |
68 | 81949 | this.explicitEnd = opts.isExplicitEnd(); |
69 | 81949 | if (opts.getVersion() != null) { |
70 | 2 | this.useVersion = opts.getVersion(); |
71 | |
} |
72 | 81949 | this.useTags = opts.getTags(); |
73 | 81949 | this.serializedNodes = new HashSet<Node>(); |
74 | 81949 | this.anchors = new HashMap<Node, String>(); |
75 | 81949 | this.lastAnchorId = 0; |
76 | 81949 | this.closed = null; |
77 | 81949 | this.explicitRoot = rootTag; |
78 | 81949 | } |
79 | |
|
80 | |
public void open() throws IOException { |
81 | 81948 | if (closed == null) { |
82 | 81946 | this.emitter.emit(new StreamStartEvent(null, null)); |
83 | 81946 | this.closed = Boolean.FALSE; |
84 | 2 | } else if (Boolean.TRUE.equals(closed)) { |
85 | 1 | throw new SerializerException("serializer is closed"); |
86 | |
} else { |
87 | 1 | throw new SerializerException("serializer is already opened"); |
88 | |
} |
89 | 81946 | } |
90 | |
|
91 | |
public void close() throws IOException { |
92 | 81935 | if (closed == null) { |
93 | 1 | throw new SerializerException("serializer is not opened"); |
94 | 81934 | } else if (!Boolean.TRUE.equals(closed)) { |
95 | 81933 | this.emitter.emit(new StreamEndEvent(null, null)); |
96 | 81933 | this.closed = Boolean.TRUE; |
97 | |
} |
98 | 81934 | } |
99 | |
|
100 | |
public void serialize(Node node) throws IOException { |
101 | 81940 | if (closed == null) { |
102 | 1 | throw new SerializerException("serializer is not opened"); |
103 | 81939 | } else if (closed) { |
104 | 1 | throw new SerializerException("serializer is closed"); |
105 | |
} |
106 | 81938 | this.emitter.emit(new DocumentStartEvent(null, null, this.explicitStart, this.useVersion, |
107 | |
useTags)); |
108 | 81938 | anchorNode(node); |
109 | 81938 | if (explicitRoot != null) { |
110 | 13071 | node.setTag(explicitRoot); |
111 | |
} |
112 | 81938 | serializeNode(node, null); |
113 | 81936 | this.emitter.emit(new DocumentEndEvent(null, null, this.explicitEnd)); |
114 | 81936 | this.serializedNodes.clear(); |
115 | 81936 | this.anchors.clear(); |
116 | 81936 | this.lastAnchorId = 0; |
117 | 81936 | } |
118 | |
|
119 | |
private void anchorNode(Node node) { |
120 | 737578 | if (node.getNodeId() == NodeId.anchor) { |
121 | 7133 | node = ((AnchorNode) node).getRealNode(); |
122 | |
} |
123 | 737578 | if (this.anchors.containsKey(node)) { |
124 | 7133 | String anchor = this.anchors.get(node); |
125 | 7133 | if (null == anchor) { |
126 | 7077 | anchor = generateAnchor(); |
127 | 7077 | this.anchors.put(node, anchor); |
128 | |
} |
129 | 7133 | } else { |
130 | 730445 | this.anchors.put(node, null); |
131 | 1 | switch (node.getNodeId()) { |
132 | |
case sequence: |
133 | 16227 | SequenceNode seqNode = (SequenceNode) node; |
134 | 16227 | List<Node> list = seqNode.getValue(); |
135 | 16227 | for (Node item : list) { |
136 | 114692 | anchorNode(item); |
137 | |
} |
138 | 16227 | break; |
139 | |
case mapping: |
140 | 51585 | MappingNode mnode = (MappingNode) node; |
141 | 51585 | List<NodeTuple> map = mnode.getValue(); |
142 | 51585 | for (NodeTuple object : map) { |
143 | 270474 | Node key = object.getKeyNode(); |
144 | 270474 | Node value = object.getValueNode(); |
145 | 270474 | anchorNode(key); |
146 | 270474 | anchorNode(value); |
147 | 270474 | } |
148 | |
break; |
149 | |
} |
150 | |
} |
151 | 737578 | } |
152 | |
|
153 | |
private String generateAnchor() { |
154 | 7077 | this.lastAnchorId++; |
155 | 7077 | NumberFormat format = NumberFormat.getNumberInstance(); |
156 | 7077 | format.setMinimumIntegerDigits(3); |
157 | 7077 | format.setGroupingUsed(false); |
158 | 7077 | String anchorId = format.format(this.lastAnchorId); |
159 | 7077 | return "id" + anchorId; |
160 | |
} |
161 | |
|
162 | |
private void serializeNode(Node node, Node parent) throws IOException { |
163 | 737578 | if (node.getNodeId() == NodeId.anchor) { |
164 | 7133 | node = ((AnchorNode) node).getRealNode(); |
165 | |
} |
166 | 737578 | String tAlias = this.anchors.get(node); |
167 | 737578 | if (this.serializedNodes.contains(node)) { |
168 | 7133 | this.emitter.emit(new AliasEvent(tAlias, null, null)); |
169 | |
} else { |
170 | 730445 | this.serializedNodes.add(node); |
171 | 730445 | switch (node.getNodeId()) { |
172 | |
case scalar: |
173 | 662633 | ScalarNode scalarNode = (ScalarNode) node; |
174 | 662633 | Tag detectedTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), true); |
175 | 662633 | Tag defaultTag = this.resolver.resolve(NodeId.scalar, scalarNode.getValue(), false); |
176 | 662633 | ImplicitTuple tuple = new ImplicitTuple(node.getTag().equals(detectedTag), node |
177 | |
.getTag().equals(defaultTag)); |
178 | 662633 | ScalarEvent event = new ScalarEvent(tAlias, node.getTag().getValue(), tuple, |
179 | |
scalarNode.getValue(), null, null, scalarNode.getStyle()); |
180 | 662633 | this.emitter.emit(event); |
181 | 662631 | break; |
182 | |
case sequence: |
183 | 16227 | SequenceNode seqNode = (SequenceNode) node; |
184 | 16227 | boolean implicitS = (node.getTag().equals(this.resolver.resolve(NodeId.sequence, |
185 | |
null, true))); |
186 | 16227 | this.emitter.emit(new SequenceStartEvent(tAlias, node.getTag().getValue(), |
187 | |
implicitS, null, null, seqNode.getFlowStyle())); |
188 | 16227 | int indexCounter = 0; |
189 | 16227 | List<Node> list = seqNode.getValue(); |
190 | 16227 | for (Node item : list) { |
191 | 114692 | serializeNode(item, node); |
192 | 114692 | indexCounter++; |
193 | |
} |
194 | 16227 | this.emitter.emit(new SequenceEndEvent(null, null)); |
195 | 16227 | break; |
196 | |
default: |
197 | 51585 | Tag implicitTag = this.resolver.resolve(NodeId.mapping, null, true); |
198 | 51585 | boolean implicitM = (node.getTag().equals(implicitTag)); |
199 | 51585 | this.emitter.emit(new MappingStartEvent(tAlias, node.getTag().getValue(), |
200 | |
implicitM, null, null, ((CollectionNode) node).getFlowStyle())); |
201 | 51585 | MappingNode mnode = (MappingNode) node; |
202 | 51585 | List<NodeTuple> map = mnode.getValue(); |
203 | 51585 | for (NodeTuple row : map) { |
204 | 270474 | Node key = row.getKeyNode(); |
205 | 270474 | Node value = row.getValueNode(); |
206 | 270474 | serializeNode(key, mnode); |
207 | 270474 | serializeNode(value, mnode); |
208 | 270474 | } |
209 | 51585 | this.emitter.emit(new MappingEndEvent(null, null)); |
210 | |
} |
211 | |
} |
212 | 737576 | } |
213 | |
} |