1 |
wakaba |
1.1 |
@@ WIP
|
2 |
|
|
|
3 |
|
|
IFClsXDef:
|
4 |
|
|
@IFQName: SerialWalker
|
5 |
|
|
@ClsQName: ManakaiDOMSerialWalker
|
6 |
|
|
|
7 |
|
|
@enDesc:
|
8 |
|
|
{ISSUE::
|
9 |
|
|
Better name?
|
10 |
|
|
}
|
11 |
|
|
|
12 |
|
|
A <IF::SerialWalker> object can be used to traverse
|
13 |
|
|
the subtree rooted by a node in document order.
|
14 |
|
|
Unlike <IF::TreeWalker> and <IF::NodeIterator>, the
|
15 |
|
|
<IF::SerialWalker> object cannot go back toward
|
16 |
|
|
nodes that had already been seen. The
|
17 |
|
|
<IF::SerialWalker>, however, revisits a node after its
|
18 |
|
|
children are visited. This might be useful when
|
19 |
|
|
an application wants to serialize a subtree in a format
|
20 |
|
|
where delimiter and / or terminator should be inserted
|
21 |
|
|
between and / or after nodes.
|
22 |
|
|
|
23 |
|
|
How the <IF::SerialWalker> works is defined by the following
|
24 |
|
|
reference algorithm. An implementation does not have to
|
25 |
|
|
implement this exact algorithm, but it <kwd:MUST> implement
|
26 |
|
|
its method so that it has the same effect as the
|
27 |
|
|
reference algorithm when the underlying subtree has not
|
28 |
|
|
been modified.
|
29 |
|
|
|
30 |
|
|
At the time of creation of the <IF::SerialWalker>,
|
31 |
|
|
the implementation <kwd:MUST> prepare a queue and
|
32 |
|
|
<kwd:MUST> initialize it by pushing the <A::SerialWalker.root> node.
|
33 |
|
|
|
34 |
|
|
{P:: When the <M::SerialWalker.nextNode> method is invoked,
|
35 |
|
|
|
36 |
|
|
- If the queue is empty, the method <kwd:MUST> return
|
37 |
|
|
<DOM::null>. It <kwd:MUST-NOT> change
|
38 |
|
|
<A::SerialWalker.currentNode>, <A::SerialWalker.currentPhase>,
|
39 |
|
|
and <A::SerialWalker.currentIndex> attributes.
|
40 |
|
|
|
41 |
|
|
{LI:: Otherwise,
|
42 |
|
|
|
43 |
|
|
- Shift a node from the queue. If the node has
|
44 |
|
|
the phase value, the method <kwd:MUST> return
|
45 |
|
|
the node. In addition, it <kwd:MUST> set
|
46 |
|
|
the <A::SerialWalker.currentNode> attribute to the node,
|
47 |
|
|
the <A::SerialWalker.currentPhase> attribute to
|
48 |
|
|
the associated phase value, and the
|
49 |
|
|
<A::SerialWalker.currentIndex> attribute to
|
50 |
|
|
the integer value that is large by one than
|
51 |
|
|
the most recent <A::SerialWalker.currentIndex> value
|
52 |
|
|
when the <A::SerialWalker.currentNode> was
|
53 |
|
|
same as the shiftted node. If it is the first time
|
54 |
|
|
the node is set to the <A::SerialWalker.currentNode>
|
55 |
|
|
attribute, the <A::SerialWalker.currentIndex>
|
56 |
|
|
attribute <kwd:MUST> set to zero.
|
57 |
|
|
|
58 |
|
|
{LI:: Otherwise, determine whether the shifted node
|
59 |
|
|
should be accepted or not, using
|
60 |
|
|
<A::SerialWalker.expandEntityReferences>,
|
61 |
|
|
<A::SerialWalker.whatToShow>, and
|
62 |
|
|
<A::SerialWalker.filter> attributes, as defined
|
63 |
|
|
for the <IF::TreeWalker> interface.
|
64 |
|
|
|
65 |
|
|
{LI:: If the node is <C::NodeFilter.FILTER_ACCEPT>ed,
|
66 |
|
|
|
67 |
|
|
= Prepend the node to the queue, with
|
68 |
|
|
phase value set to <C::SerialWalker.POST_PHASE>.
|
69 |
|
|
|
70 |
|
|
= Prepend the child nodes of the node, if any,
|
71 |
|
|
to the queue keeping the document order,
|
72 |
|
|
without phase value. That is, the first child
|
73 |
|
|
<kwd:MUST> be located at the top (first
|
74 |
|
|
position) of the queue.
|
75 |
|
|
|
76 |
|
|
= Prepend the node to the queue, with
|
77 |
|
|
phase value set to <C::SerialWalker.PRE_PHASE>.
|
78 |
|
|
|
79 |
|
|
= If the node has a previous sibling in the logical view,
|
80 |
|
|
preprend the parent node of the node in the logical
|
81 |
|
|
view, with phase value set to <C::SerialWalker.IN_PHASE>.
|
82 |
|
|
|
83 |
|
|
= Invoke the algorithm recursively.
|
84 |
|
|
|
85 |
|
|
}
|
86 |
|
|
|
87 |
|
|
{LI:: If the node is <C::NodeFilter.FILTER_SKIP>ped,
|
88 |
|
|
|
89 |
|
|
= Prepend the child nodes of the node, if any,
|
90 |
|
|
to the queue keeping the document order,
|
91 |
|
|
without phase value. That is, the first child
|
92 |
|
|
<kwd:MUST> be located at the top (first
|
93 |
|
|
position) of the queue.
|
94 |
|
|
|
95 |
|
|
= Invoke the algorithm recursively.
|
96 |
|
|
|
97 |
|
|
}
|
98 |
|
|
|
99 |
|
|
{LI:: If the node is <C::NodeFilter.MANAKAI_FILTER_OPAQUE>,
|
100 |
|
|
|
101 |
|
|
= Prepend the node to the queue, with
|
102 |
|
|
phase value set to <C::SerialWalker.POST_PHASE>.
|
103 |
|
|
|
104 |
|
|
= Prepend the node to the queue, with
|
105 |
|
|
phase value set to <C::SerialWalker.PRE_PHASE>.
|
106 |
|
|
|
107 |
|
|
= If the node has a previous sibling in the logical view,
|
108 |
|
|
preprend the parent node of the node in the logical
|
109 |
|
|
view, with phase value set to <C::SerialWalker.IN_PHASE>.
|
110 |
|
|
|
111 |
|
|
= Invoke the algorithm recursively.
|
112 |
|
|
|
113 |
|
|
}
|
114 |
|
|
|
115 |
|
|
- Otherwise, invoke the algorithm recursively.
|
116 |
|
|
|
117 |
|
|
}
|
118 |
|
|
}
|
119 |
|
|
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
{NOTE::
|
123 |
|
|
This algorithm will stop unless nodes are simulataneously
|
124 |
|
|
populated to the underlying tree by application via
|
125 |
|
|
e.g. <IF::NodeFilter>.
|
126 |
|
|
}
|
127 |
|
|
|
128 |
|
|
Implementation <kwd:MAY> choose to implement the <IF::SerialWalker>
|
129 |
|
|
using another algorithm. In particular, when the <IF::NodeFilter>
|
130 |
|
|
is invoked might vary across implementations. Implementations
|
131 |
|
|
should try to return the same effect as the reference algorithm
|
132 |
|
|
even if the underlying subtree is modified, but applications
|
133 |
|
|
<kwd:MUST-NOT> rely on the particular implementation's behavior.
|
134 |
|
|
|
135 |
|
|
As long as the underlying subtree is not modified, a node will
|
136 |
|
|
never set to the <A::SerialWalker.currentNode> attribute
|
137 |
|
|
with the <A::SerialWalker.currentPhase> of <C::SerialWalker.PRE_PHASE>.
|
138 |
|
|
If the underlying subtree is modified, depending on how
|
139 |
|
|
the method is implemented, it might be in case. For
|
140 |
|
|
the purpose of description below, such duplication was considered
|
141 |
|
|
as if they were different nodes.
|
142 |
|
|
|
143 |
|
|
{P:: Even if the underlying subtree has been modified during
|
144 |
|
|
the traversal, the implementation <kwd:MUST> ensure
|
145 |
|
|
the following conditions are met:
|
146 |
|
|
|
147 |
|
|
- A node <kwd:MUST-NOT> be set to the <A::SerialWalker.currentNode>
|
148 |
|
|
attribute with the <A::SerialWalker.currentPhase> of
|
149 |
|
|
<C::SerialWalker.PRE_PHASE> or <C::SerialWalker.POST_PHASE>
|
150 |
|
|
more than once respectively.
|
151 |
|
|
|
152 |
|
|
- A node <kwd:MUST-NOT> be set to the <A::SerialWalker.currentNode>
|
153 |
|
|
attribute with the <A::SerialWalker.currentPhase> of
|
154 |
|
|
<C::SerialWalker.IN_PHASE> before it is once set to
|
155 |
|
|
the same node with the <A::SerialWalker.currentPhase>
|
156 |
|
|
of <C::SerialWalker.PRE_PHASE>, or after it is once set
|
157 |
|
|
to the same node with the <A::SerialWalker.currentPhase>
|
158 |
|
|
of <C::SerialWalker.POST_PHASE>.
|
159 |
|
|
|
160 |
|
|
- A node <kwd:MUST-NOT> be set to the <A::SerialWalker.currentNode>
|
161 |
|
|
attribute with the <A::SerialWalker.currentPhase> of
|
162 |
|
|
<C::SerialWalker.POST_PHASE> before it is once set to
|
163 |
|
|
the same node with the <A::SerialWalker.currentPhase>
|
164 |
|
|
of <C::SerialWalker.PRE_PHASE>.
|
165 |
|
|
|
166 |
|
|
- A node <kwd:MUST> be set to the <A::SerialWalker.currentNode>
|
167 |
|
|
attribute with the <A::SerialWalker.currentPhase> of
|
168 |
|
|
<C::SerialWalker.POST_PHASE> later if it is once set to
|
169 |
|
|
the same node with the <A::SerialWalker.currentPhase>
|
170 |
|
|
of <C::SerialWalker.PRE_PHASE>.
|
171 |
|
|
|
172 |
|
|
- The <A::SerialWalker.currentPhase> <kwd:MUST-NOT> set
|
173 |
|
|
to <C::SerialWalker.PRE_PHASE> unless its value is
|
174 |
|
|
<C::SerialWalker.PRE_PHASE> or <C::SerialWalker.IN_PHASE>.
|
175 |
|
|
|
176 |
|
|
- The <A::SerialWalker.currentPhase> <kwd:MUST-NOT> set
|
177 |
|
|
to <C::SerialWalker.IN_PHASE> unless its value is
|
178 |
|
|
<C::SerialWalker.POST_PHASE>.
|
179 |
|
|
|
180 |
|
|
- The <A::SerialWalker.currentPhase> <kwd:MUST-NOT> set
|
181 |
|
|
to <C::SerialWalker.POST_PHASE> unless its value is
|
182 |
|
|
<C::SerialWalker.PRE_PHASE> or <C::SerialWalker.POST_PHASE>.
|
183 |
|
|
|
184 |
|
|
- If a node <VAR::N> is set to the <A::SerialWalker.currentNode>
|
185 |
|
|
attribute and then another node <VAR::M> is set to the attribute
|
186 |
|
|
with both <A::SerialWalker.currentPhase> of <C::SerialWalker.PRE_PHASE>,
|
187 |
|
|
the <A::SerialWalker.currentNode> attribute <kwd:MUST-NOT> be set to
|
188 |
|
|
<VAR::N> with <A::SerialWalker.currentPhase> of
|
189 |
|
|
<C::SerialWalker.POST_PHASE> before once the
|
190 |
|
|
<A::SerialWalker.currentNode> attribute is set to
|
191 |
|
|
<VAR::M> with <A::SerialWalker.currentPhase> of
|
192 |
|
|
<C::SerialWalker.POST_PHASE>.
|
193 |
|
|
|
194 |
|
|
- For each time the <A::SerialWalker.currentNode> attribute is
|
195 |
|
|
set to a node, the <A::SerialWalker.currentIndex> <kwd:MUST>
|
196 |
|
|
be increased by one. If the node is set to the attribute
|
197 |
|
|
for the first time, the <A::SerialWalker.currentIndex>
|
198 |
|
|
<kwd:MUST> be set to zero. That is, with and only with
|
199 |
|
|
<C::SerialWalker.PRE_PHASE> the <A::SerialWalker.currentIndex>
|
200 |
|
|
can be zero.
|
201 |
|
|
}
|
202 |
|
|
|
203 |
|
|
@CODE:
|
204 |
|
|
@@QName: createSWForTest
|
205 |
|
|
@@PerlDef:
|
206 |
|
|
__CODE{tc|createEmptyDocumentForTest:: $doc => $doc}__;
|
207 |
|
|
|
208 |
|
|
my $docel = $doc-><M::Document.createElement> ('docel');
|
209 |
|
|
|
210 |
|
|
$doc-><M::Node.appendChild> ($docel);
|
211 |
|
|
|
212 |
|
|
my $doctrv = $doc-><M::Node.getFeature> ('Traversal', '2.0');
|
213 |
|
|
$sw = $doctrv-><M::DocumentTraversal.manakaiCreateSerialWalker> ($docel);
|
214 |
|
|
|
215 |
|
|
@LXAttr:
|
216 |
|
|
@@Name: root
|
217 |
|
|
@@enDesc:
|
218 |
|
|
The root node of the <IF::SerialWalker>.
|
219 |
|
|
@@Type: Node
|
220 |
|
|
@@Get:
|
221 |
|
|
@@@enDesc:
|
222 |
|
|
The root node set when the <IF::SerialWalker> is created.
|
223 |
|
|
@@@PerlDef:
|
224 |
|
|
$r = $self->{root};
|
225 |
|
|
|
226 |
|
|
@LXAttr:
|
227 |
|
|
@@Name: currentNode
|
228 |
|
|
@@enDesc:
|
229 |
|
|
The current node of the <IF::SerialWalker>.
|
230 |
|
|
|
231 |
|
|
{NOTE::
|
232 |
|
|
Unlike <IF::TreeWalker>, the <A::SerialWalker.currentNode>
|
233 |
|
|
attribute is read-only.
|
234 |
|
|
}
|
235 |
|
|
@@Type: Node
|
236 |
|
|
@@Get:
|
237 |
|
|
@@@enDesc:
|
238 |
|
|
The current node.
|
239 |
|
|
@@@PerlDef:
|
240 |
|
|
$r = $self->{current_node};
|
241 |
|
|
|
242 |
|
|
@mShortConstGroup:
|
243 |
|
|
@@IFQName: SerialWalkerPhase
|
244 |
|
|
@@enDesc:
|
245 |
|
|
An integer to indicate a phase of <IF::SerialWalker>.
|
246 |
|
|
|
247 |
|
|
@@mConst:
|
248 |
|
|
@@@Name: PRE_PHASE
|
249 |
|
|
@@@intValue: 1
|
250 |
|
|
@@@enDesc:
|
251 |
|
|
The <A::SerialWalker.currentNode> is visited by
|
252 |
|
|
the <IF::SerialWalker> for the first time. It is
|
253 |
|
|
expected that the same node will be revisited
|
254 |
|
|
with <A::SerialWalker.currentPhase> of
|
255 |
|
|
<C::SerialWalker.IN_PHASE> (optionally) and
|
256 |
|
|
<C::SerialWalker.POST_PHASE> later.
|
257 |
|
|
@@mConst:
|
258 |
|
|
@@@Name: IN_PHASE
|
259 |
|
|
@@@intValue: 2
|
260 |
|
|
@@@enDesc:
|
261 |
|
|
The <A::SerialWalker.currentNode> is visited
|
262 |
|
|
by the <IF::SerialWalker>, not for the first
|
263 |
|
|
or last time, between visitings to its two child nodes.
|
264 |
|
|
@@mConst:
|
265 |
|
|
@@@Name: POST_PHASE
|
266 |
|
|
@@@intValue: 3
|
267 |
|
|
@@@enDesc:
|
268 |
|
|
The <A::SerialWalker.currentNode> is visited
|
269 |
|
|
by the <IF::SerialWalker> for the last time.
|
270 |
|
|
|
271 |
|
|
@LXAttr:
|
272 |
|
|
@@Name: currentPhase
|
273 |
|
|
@@enDesc:
|
274 |
|
|
The current phase of the <IF::SerialWalker>.
|
275 |
|
|
@@Type: unsignedShort
|
276 |
|
|
@@actualType: SerialWalkerPhase
|
277 |
|
|
@@Get:
|
278 |
|
|
@@@enDesc:
|
279 |
|
|
An integer to indicate the current phase.
|
280 |
|
|
@@@PerlDef:
|
281 |
|
|
$r = $self->{current_phase};
|
282 |
|
|
|
283 |
|
|
@LXAttr:
|
284 |
|
|
@@Name: currentIndex
|
285 |
|
|
@@enDesc:
|
286 |
|
|
The current index of the <IF::SerialWalker>. The
|
287 |
|
|
<DFN::current index> represents how many times the
|
288 |
|
|
<A::SerialWalker.currentNode> is exposed through
|
289 |
|
|
the <IF::SerialWalker>.
|
290 |
|
|
@@Type: unsignedLong
|
291 |
|
|
@@Get:
|
292 |
|
|
@@@enDesc:
|
293 |
|
|
An integer to indicate the current index.
|
294 |
|
|
@@@PerlDef:
|
295 |
|
|
$r = $self->{current_index};
|
296 |
|
|
|
297 |
|
|
@LXAttr:
|
298 |
|
|
@@Name: expandEntityReferences
|
299 |
|
|
@@enDesc:
|
300 |
|
|
The value of the flag that determines whether the children of
|
301 |
|
|
<IF::tx|EntityReference> nodes are visible to the <IF::SerialWalker>.
|
302 |
|
|
|
303 |
|
|
{NOTE::
|
304 |
|
|
To produce a view of the document that has entity references
|
305 |
|
|
expanded and does not expose the <IF::tx|EntityReference> nodes
|
306 |
|
|
themselves, use the <A::SerialWalker.whatToShow> flags to hide the
|
307 |
|
|
<IF::tx|EntityReference> nodes and set the
|
308 |
|
|
<A::SerialWalker.expandEntityReferences> flag to <DOM::true>
|
309 |
|
|
when creating the <IF::SerialWalker>.
|
310 |
|
|
|
311 |
|
|
To produce a view of the document that has <IF::tx|EntityReference>
|
312 |
|
|
nodes but no entity expansion, use the <A::SerialWalker.whatToShow>
|
313 |
|
|
flags to show the <IF::tx|EntityReference> nodes and set the
|
314 |
|
|
<A::SerialWalker.expandEntityReferences> flag to <DOM::false>
|
315 |
|
|
when creating the <IF::SerialWalker>.
|
316 |
|
|
}
|
317 |
|
|
@@Type: boolean
|
318 |
|
|
@@Get:
|
319 |
|
|
@@@enDesc:
|
320 |
|
|
The <CODE::entityReferenceExpansion> value that
|
321 |
|
|
was specified when the <IF::SerialWalker> was created.
|
322 |
|
|
@@@TrueCase:
|
323 |
|
|
@@@@enDesc:
|
324 |
|
|
The children and their descendants of <IF::tx|EntityReference>
|
325 |
|
|
nodes will <EM::not> be rejected. Note that
|
326 |
|
|
the <A::SerialWalker.whatToShow> flags and the
|
327 |
|
|
<A::SerialWalker.filter> set to the <IF::SerialWalker>
|
328 |
|
|
might reject them as usual way.
|
329 |
|
|
@@@FalseCase:
|
330 |
|
|
@@@@enDesc:
|
331 |
|
|
The children and their descendants of entity reference nodes
|
332 |
|
|
will be rejected. This rejection takes precedence over
|
333 |
|
|
the <A::SerialWalker.whatToShow> flags and the
|
334 |
|
|
<A::SerialWalker.filter> set to the
|
335 |
|
|
<IF::SerialWalker>, if any.
|
336 |
|
|
@@@PerlDef:
|
337 |
|
|
$r = $self->{expand_entity_references};
|
338 |
|
|
|
339 |
|
|
@LXAttr:
|
340 |
|
|
@@Name: filter
|
341 |
|
|
@@enDesc:
|
342 |
|
|
The filter used to screen nodes.
|
343 |
|
|
@@Type: NodeFilter
|
344 |
|
|
@@Get:
|
345 |
|
|
@@@enDesc:
|
346 |
|
|
The <IF::NodeFilter> that was specified when the
|
347 |
|
|
<IF::SerialWalker> was created.
|
348 |
|
|
@@@nullCase:
|
349 |
|
|
@@@@enDesc:
|
350 |
|
|
If no <IF::NodeFilter> was specified when the
|
351 |
|
|
<IF::SerialWalker> was created.
|
352 |
|
|
@@@PerlDef:
|
353 |
|
|
$r = $self->{filter};
|
354 |
|
|
|
355 |
|
|
@LXAttr:
|
356 |
|
|
@@Name: whatToShow
|
357 |
|
|
@@enDesc:
|
358 |
|
|
The flags that determines which node types are presented
|
359 |
|
|
via the <IF::SerialWalker>. The available set of constants
|
360 |
|
|
is defined in the <IF::NodeFilter> interface.
|
361 |
|
|
|
362 |
|
|
Nodes not accepted by the <A::SerialWalker.whatToShow>
|
363 |
|
|
flags will be skipped, but their children may still be
|
364 |
|
|
considered. This skip takes precedence over the
|
365 |
|
|
<A::SerialWalker.filter> set to the <IF::SerialWalker>, if any.
|
366 |
|
|
@@Type: unsignedShort
|
367 |
|
|
@@actualType: WhatToShow
|
368 |
|
|
@@Get:
|
369 |
|
|
@@@enDesc:
|
370 |
|
|
The <CODE::whatToShow> value that was specified
|
371 |
|
|
when the <IF::SerialWalker> was created.
|
372 |
|
|
@@@PerlDef:
|
373 |
|
|
$r = $self->{what_to_show};
|
374 |
|
|
|
375 |
|
|
@LXMethod:
|
376 |
|
|
@@Name: nextNode
|
377 |
|
|
@@enDesc:
|
378 |
|
|
Returns the node next to the <A::SerialWalker.currentNode>
|
379 |
|
|
of the <IF::SerialWalker>.
|
380 |
|
|
@@Return:
|
381 |
|
|
@@@Type: Node
|
382 |
|
|
@@@enDesc:
|
383 |
|
|
The next node.
|
384 |
|
|
@@@nullCase:
|
385 |
|
|
@@@@enDesc:
|
386 |
|
|
If no next node. |