1313package scala
1414package xml
1515
16+ import scala .annotation .tailrec
1617import scala .collection .mutable
1718import scala .language .implicitConversions
1819import scala .collection .Seq
@@ -191,9 +192,8 @@ object Utility extends AnyRef with parsing.TokenTests {
191192 decodeEntities : Boolean = true ,
192193 preserveWhitespace : Boolean = false ,
193194 minimizeTags : Boolean = false
194- ): StringBuilder = {
195+ ): StringBuilder =
195196 serialize(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, if (minimizeTags) MinimizeMode .Always else MinimizeMode .Never )
196- }
197197
198198 /**
199199 * Serialize an XML Node to a StringBuilder.
@@ -212,32 +212,64 @@ object Utility extends AnyRef with parsing.TokenTests {
212212 preserveWhitespace : Boolean = false ,
213213 minimizeTags : MinimizeMode .Value = MinimizeMode .Default
214214 ): StringBuilder = {
215- x match {
216- case c : Comment => if (! stripComments) c.buildString(sb); sb
217- case s : SpecialNode => s.buildString(sb)
218- case g : Group =>
219- for (c <- g.nodes) serialize(c, g.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags); sb
220- case el : Elem =>
221- // print tag with namespace declarations
222- sb.append('<' )
223- el.nameToString(sb)
224- if (el.attributes.ne(null )) el.attributes.buildString(sb)
225- el.scope.buildString(sb, pscope)
226- if (el.child.isEmpty &&
227- (minimizeTags == MinimizeMode .Always ||
228- (minimizeTags == MinimizeMode .Default && el.minimizeEmpty))) {
229- // no children, so use short form: <xyz .../>
230- sb.append(" />" )
231- } else {
232- // children, so use long form: <xyz ...>...</xyz>
233- sb.append('>' )
234- sequenceToXML(el.child, el.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
215+ serializeImpl(List (x), pscope, false , stripComments, minimizeTags, sb)
216+ sb
217+ }
218+
219+ private def serializeImpl (
220+ ns : Seq [Node ],
221+ pscope : NamespaceBinding ,
222+ spaced : Boolean ,
223+ stripComments : Boolean ,
224+ minimizeTags : MinimizeMode .Value ,
225+ sb : StringBuilder
226+ ): Unit = {
227+ @ tailrec def ser (nss : List [Seq [Node ]], pscopes : List [NamespaceBinding ], spaced : List [Boolean ], toClose : List [Node ]): Unit = nss match {
228+ case List (ns) if ns.isEmpty =>
229+ case ns :: rests if ns.isEmpty =>
230+ if (toClose.head != null ) {
235231 sb.append(" </" )
236- el .nameToString(sb)
232+ toClose.head .nameToString(sb)
237233 sb.append('>' )
238234 }
239- case _ => throw new IllegalArgumentException (" Don't know how to serialize a " + x.getClass.getName)
235+ ser(rests, pscopes.tail, spaced.tail, toClose.tail)
236+ case ns1 :: r =>
237+ val (n, ns) = (ns1.head, ns1.tail)
238+ def sp (): Unit = if (ns.nonEmpty && spaced.head) sb.append(' ' )
239+ n match {
240+ case c : Comment =>
241+ if (! stripComments) {
242+ c.buildString(sb)
243+ sp()
244+ }
245+ ser(ns :: r, pscopes, spaced, toClose)
246+ case s : SpecialNode =>
247+ s.buildString(sb)
248+ sp()
249+ ser(ns :: r, pscopes, spaced, toClose)
250+ case g : Group =>
251+ ser(g.nodes :: ns :: r, g.scope :: pscopes, false :: spaced, null :: toClose)
252+ case e : Elem =>
253+ sb.append('<' )
254+ e.nameToString(sb)
255+ if (e.attributes.ne(null )) e.attributes.buildString(sb)
256+ e.scope.buildString(sb, pscopes.head)
257+ if (e.child.isEmpty &&
258+ (minimizeTags == MinimizeMode .Always ||
259+ (minimizeTags == MinimizeMode .Default && e.minimizeEmpty))) {
260+ // no children, so use short form: <xyz .../>
261+ sb.append(" />" )
262+ sp()
263+ ser(ns :: r, pscopes, spaced, toClose)
264+ } else {
265+ sb.append('>' )
266+ val csp = e.child.forall(isAtomAndNotText)
267+ ser(e.child :: ns :: r, e.scope :: pscopes, csp :: spaced, e :: toClose)
268+ }
269+ case n => throw new IllegalArgumentException (" Don't know how to serialize a " + n.getClass.getName)
270+ }
240271 }
272+ ser(List (ns), List (pscope), List (spaced), Nil )
241273 }
242274
243275 def sequenceToXML (
@@ -248,18 +280,9 @@ object Utility extends AnyRef with parsing.TokenTests {
248280 decodeEntities : Boolean = true ,
249281 preserveWhitespace : Boolean = false ,
250282 minimizeTags : MinimizeMode .Value = MinimizeMode .Default
251- ): Unit = {
252- if (children.isEmpty) ()
253- else if (children.forall(isAtomAndNotText)) { // add space
254- val it : Iterator [Node ] = children.iterator
255- val f : Node = it.next()
256- serialize(f, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
257- while (it.hasNext) {
258- val x : Node = it.next()
259- sb.append(' ' )
260- serialize(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
261- }
262- } else children.foreach { serialize(_, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) }
283+ ): Unit = if (children.nonEmpty) {
284+ val spaced = children.forall(isAtomAndNotText)
285+ serializeImpl(children, pscope, spaced, stripComments, minimizeTags, sb)
263286 }
264287
265288 def splitName (name : String ): (Option [String ], String ) = {
0 commit comments