9
9
package scala
10
10
package xml
11
11
12
+ import scala .annotation .tailrec
12
13
import scala .collection .mutable
13
14
import scala .language .implicitConversions
14
15
import scala .collection .Seq
@@ -187,9 +188,7 @@ object Utility extends AnyRef with parsing.TokenTests {
187
188
decodeEntities : Boolean = true ,
188
189
preserveWhitespace : Boolean = false ,
189
190
minimizeTags : Boolean = false ): StringBuilder =
190
- {
191
191
serialize(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, if (minimizeTags) MinimizeMode .Always else MinimizeMode .Never )
192
- }
193
192
194
193
/**
195
194
* Serialize an XML Node to a StringBuilder.
@@ -206,35 +205,66 @@ object Utility extends AnyRef with parsing.TokenTests {
206
205
stripComments : Boolean = false ,
207
206
decodeEntities : Boolean = true ,
208
207
preserveWhitespace : Boolean = false ,
209
- minimizeTags : MinimizeMode .Value = MinimizeMode .Default ): StringBuilder =
210
- {
211
- x match {
212
- case c : Comment => if (! stripComments) c buildString sb; sb
213
- case s : SpecialNode => s buildString sb
214
- case g : Group =>
215
- for (c <- g.nodes) serialize(c, g.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags); sb
216
- case el : Elem =>
217
- // print tag with namespace declarations
218
- sb.append('<' )
219
- el.nameToString(sb)
220
- if (el.attributes ne null ) el.attributes.buildString(sb)
221
- el.scope.buildString(sb, pscope)
222
- if (el.child.isEmpty &&
223
- (minimizeTags == MinimizeMode .Always ||
224
- (minimizeTags == MinimizeMode .Default && el.minimizeEmpty))) {
225
- // no children, so use short form: <xyz .../>
226
- sb.append(" />" )
227
- } else {
228
- // children, so use long form: <xyz ...>...</xyz>
229
- sb.append('>' )
230
- sequenceToXML(el.child, el.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
231
- sb.append(" </" )
232
- el.nameToString(sb)
233
- sb.append('>' )
234
- }
235
- case _ => throw new IllegalArgumentException (" Don't know how to serialize a " + x.getClass.getName)
236
- }
208
+ minimizeTags : MinimizeMode .Value = MinimizeMode .Default
209
+ ): StringBuilder = {
210
+ serializeImpl(List (x), pscope, false , stripComments, minimizeTags, sb)
211
+ sb
212
+ }
213
+
214
+ private def serializeImpl (
215
+ ns : Seq [Node ],
216
+ pscope : NamespaceBinding ,
217
+ spaced : Boolean ,
218
+ stripComments : Boolean ,
219
+ minimizeTags : MinimizeMode .Value ,
220
+ sb : StringBuilder
221
+ ): Unit = {
222
+ @ tailrec def ser (nss : List [List [Node ]], pscopes : List [NamespaceBinding ], spaced : List [Boolean ], toClose : List [Node ]): Unit = nss match {
223
+ case List (Nil ) =>
224
+ case Nil :: rests =>
225
+ if (toClose.head != null ) {
226
+ sb.append(" </" )
227
+ toClose.head.nameToString(sb)
228
+ sb.append('>' )
229
+ }
230
+ ser(rests, pscopes.tail, spaced.tail, toClose.tail)
231
+ case (n :: ns) :: r =>
232
+ def sp (): Unit = if (ns.nonEmpty && spaced.head) sb.append(' ' )
233
+ n match {
234
+ case c : Comment =>
235
+ if (! stripComments) {
236
+ c.buildString(sb)
237
+ sp()
238
+ }
239
+ ser(ns :: r, pscopes, spaced, toClose)
240
+ case s : SpecialNode =>
241
+ s.buildString(sb)
242
+ sp()
243
+ ser(ns :: r, pscopes, spaced, toClose)
244
+ case g : Group =>
245
+ ser(g.nodes.toList :: ns :: r, g.scope :: pscopes, false :: spaced, null :: toClose)
246
+ case e : Elem =>
247
+ sb.append('<' )
248
+ e.nameToString(sb)
249
+ if (e.attributes.ne(null )) e.attributes.buildString(sb)
250
+ e.scope.buildString(sb, pscopes.head)
251
+ if (e.child.isEmpty &&
252
+ (minimizeTags == MinimizeMode .Always ||
253
+ (minimizeTags == MinimizeMode .Default && e.minimizeEmpty))) {
254
+ // no children, so use short form: <xyz .../>
255
+ sb.append(" />" )
256
+ sp()
257
+ ser(ns :: r, pscopes, spaced, toClose)
258
+ } else {
259
+ sb.append('>' )
260
+ val csp = e.child.forall(isAtomAndNotText)
261
+ ser(e.child.toList :: ns :: r, e.scope :: pscopes, csp :: spaced, e :: toClose)
262
+ }
263
+ case n => throw new IllegalArgumentException (" Don't know how to serialize a " + n.getClass.getName)
264
+ }
237
265
}
266
+ ser(List (ns.toList), List (pscope), List (spaced), Nil )
267
+ }
238
268
239
269
def sequenceToXML (
240
270
children : Seq [Node ],
@@ -243,20 +273,11 @@ object Utility extends AnyRef with parsing.TokenTests {
243
273
stripComments : Boolean = false ,
244
274
decodeEntities : Boolean = true ,
245
275
preserveWhitespace : Boolean = false ,
246
- minimizeTags : MinimizeMode .Value = MinimizeMode .Default ): Unit =
247
- {
248
- if (children.isEmpty) return
249
- else if (children forall isAtomAndNotText) { // add space
250
- val it = children.iterator
251
- val f = it.next()
252
- serialize(f, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
253
- while (it.hasNext) {
254
- val x = it.next()
255
- sb.append(' ' )
256
- serialize(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
257
- }
258
- } else children foreach { serialize(_, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) }
259
- }
276
+ minimizeTags : MinimizeMode .Value = MinimizeMode .Default
277
+ ): Unit = if (children.nonEmpty) {
278
+ val spaced = children.forall(isAtomAndNotText)
279
+ serializeImpl(children, pscope, spaced, stripComments, minimizeTags, sb)
280
+ }
260
281
261
282
/**
262
283
* Returns prefix of qualified name if any.
0 commit comments