@@ -92,10 +92,10 @@ public static String escape(CharSequence s) {
92
92
private static final char [] ATTRIBUTE_EQUALS = new char [] { '=' , '"' };
93
93
private static final char [] CLOSE_EMPTY_TAG = new char [] { '/' , '>' };
94
94
private static final char [] START_CLOSE = new char [] { '<' , '/' };
95
- private static final char [] START_CDATA = new char [] { '[' , 'C' , 'D' , 'A' , 'T' , 'A' , '[' };
96
- private static final char [] END_CDATA = new char [] { ']' , ']' };
97
- private static final char [] START_COMMENT = new char [] { '<' , '!' , '-' , '-' , ' ' };
98
- private static final char [] END_COMMENT = new char [] { ' ' , ' -' , '-' , '>' };
95
+ private static final char [] START_CDATA = new char [] { '<' , '!' , ' [' , 'C' , 'D' , 'A' , 'T' , 'A' , '[' };
96
+ private static final char [] END_CDATA = new char [] { ']' , ']' , '>' };
97
+ private static final char [] START_COMMENT = new char [] { '<' , '!' , '-' , '-' };
98
+ private static final char [] END_COMMENT = new char [] { '-' , '-' , '>' };
99
99
100
100
private static final char [] PRETTY_END_TAG = new char [] { '>' , '\n' };
101
101
@@ -105,7 +105,7 @@ public static String escape(CharSequence s) {
105
105
* Start the document with the XML processing instruction if needed, and opening the root element.
106
106
* @param rootNamespaceURI namespace of the root element
107
107
* @param rootLocalName name of the root element
108
- * @param namespaces mapping from namespace URI and prefix, prefix may be empty for default namespace
108
+ * @param namespaces mapping from namespace URI to prefix, prefix may be empty for default namespace
109
109
*/
110
110
public IAsync <IOException > start (String rootNamespaceURI , String rootLocalName , Map <String , String > namespaces ) {
111
111
if (includeXMLDeclaration ) {
@@ -292,7 +292,8 @@ public IAsync<IOException> addCData(CharSequence data) {
292
292
if (ctx .open )
293
293
endOfAttributes (ctx );
294
294
if (pretty ) {
295
- writer .write ('\n' );
295
+ if (lastNodeType != Node .ELEMENT_NODE && lastNodeType != Node .COMMENT_NODE && lastNodeType != Node .CDATA_SECTION_NODE )
296
+ writer .write ('\n' );
296
297
indent ();
297
298
}
298
299
writer .write (START_CDATA );
@@ -310,7 +311,8 @@ public IAsync<IOException> addComment(CharSequence comment) {
310
311
if (ctx != null && ctx .open )
311
312
endOfAttributes (ctx );
312
313
if (pretty ) {
313
- writer .write ('\n' );
314
+ if (lastNodeType != Node .ELEMENT_NODE && lastNodeType != Node .COMMENT_NODE && lastNodeType != Node .CDATA_SECTION_NODE )
315
+ writer .write ('\n' );
314
316
indent ();
315
317
}
316
318
writer .write (START_COMMENT );
@@ -322,6 +324,8 @@ public IAsync<IOException> addComment(CharSequence comment) {
322
324
return writer .write ('\n' );
323
325
}
324
326
327
+ private static final String DOM_TASK_DESCRIPTION = "Write DOM" ;
328
+
325
329
/** Write the given DOM element. */
326
330
public IAsync <IOException > write (Element element ) {
327
331
String name = element .getLocalName ();
@@ -333,13 +337,48 @@ public IAsync<IOException> write(Element element) {
333
337
namespaces = new HashMap <>(5 );
334
338
namespaces .put (uri , prefix );
335
339
}
336
- openElement (uri , name , namespaces );
340
+ IAsync <IOException > open = openElement (uri , name , namespaces );
341
+ if (open .isDone ())
342
+ return writeAttributes (element );
343
+ Async <IOException > sp = new Async <>();
344
+ open .thenStart (new Task .Cpu .FromRunnable (DOM_TASK_DESCRIPTION , output .getPriority (), () ->
345
+ writeAttributes (element ).onDone (sp )
346
+ ), sp );
347
+ return sp ;
348
+ }
349
+
350
+ private IAsync <IOException > writeAttributes (Element element ) {
337
351
NamedNodeMap attrs = element .getAttributes ();
338
- if (attrs != null )
339
- for (int i = 0 ; i < attrs .getLength (); ++i ) {
340
- Node a = attrs .item (i );
341
- addAttribute (a .getNodeName (), a .getNodeValue ());
352
+ if (attrs != null && attrs .getLength () > 0 )
353
+ return writeAttribute (element , attrs , 0 );
354
+ return writeChildren (element );
355
+ }
356
+
357
+ private IAsync <IOException > writeAttribute (Element element , NamedNodeMap attrs , int attrIndex ) {
358
+ do {
359
+ Node a = attrs .item (attrIndex );
360
+ IAsync <IOException > sp = addAttribute (a .getNodeName (), a .getNodeValue ());
361
+ if (sp .isDone ()) {
362
+ if (sp .hasError ()) return sp ;
363
+ attrIndex ++;
364
+ if (attrIndex == attrs .getLength ())
365
+ return writeChildren (element );
366
+ continue ;
342
367
}
368
+ Async <IOException > result = new Async <>();
369
+ int nextIndex = attrIndex + 1 ;
370
+ sp .thenStart (new Task .Cpu .FromRunnable (DOM_TASK_DESCRIPTION , output .getPriority (), () -> {
371
+ if (nextIndex == attrs .getLength ()) {
372
+ writeChildren (element ).onDone (result );
373
+ return ;
374
+ }
375
+ writeAttribute (element , attrs , nextIndex ).onDone (result );
376
+ }), result );
377
+ return result ;
378
+ } while (true );
379
+ }
380
+
381
+ private IAsync <IOException > writeChildren (Element element ) {
343
382
NodeList children = element .getChildNodes ();
344
383
if (children .getLength () == 0 )
345
384
return closeElement ();
@@ -349,7 +388,7 @@ public IAsync<IOException> write(Element element) {
349
388
return writeChild (children , 0 );
350
389
}
351
390
Async <IOException > sp = new Async <>();
352
- open .thenStart (new Task .Cpu .FromRunnable ("Write DOM" , output .getPriority (), () ->
391
+ open .thenStart (new Task .Cpu .FromRunnable (DOM_TASK_DESCRIPTION , output .getPriority (), () ->
353
392
writeChild (children , 0 ).onDone (sp )
354
393
), sp );
355
394
return sp ;
@@ -372,14 +411,14 @@ else if (child instanceof Text)
372
411
if (sp .isDone ()) {
373
412
if (sp .hasError ()) return sp ;
374
413
childIndex ++;
375
- if (childIndex == children .getLength ()) return sp ;
414
+ if (childIndex == children .getLength ()) return closeElement () ;
376
415
continue ;
377
416
}
378
417
Async <IOException > result = new Async <>();
379
418
int nextIndex = childIndex + 1 ;
380
- sp .thenStart (new Task .Cpu .FromRunnable ("Write DOM" , output .getPriority (), () -> {
419
+ sp .thenStart (new Task .Cpu .FromRunnable (DOM_TASK_DESCRIPTION , output .getPriority (), () -> {
381
420
if (nextIndex == children .getLength ()) {
382
- result . unblock ( );
421
+ closeElement (). onDone ( result );
383
422
return ;
384
423
}
385
424
writeChild (children , nextIndex ).onDone (result );
0 commit comments