diff options
-rw-r--r-- | src/library/scala/xml/Utility.scala | 69 | ||||
-rw-r--r-- | src/library/scala/xml/Xhtml.scala | 55 |
2 files changed, 80 insertions, 44 deletions
diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 4b749db9e6..f7f7171580 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -28,6 +28,19 @@ object Utility extends AnyRef with parsing.TokenTests f(sb) sb.toString } + private[xml] def isAtomAndNotText(x: Node) = x.isInstanceOf[Atom[_]] && !x.isInstanceOf[Text] + + // XXX this is very ham fisted at the moment + class XMLOptions { + val stripComments: Boolean = false + val decodeEntities: Boolean = true + val preserveWhitespace: Boolean = false + val minimizeTags: Boolean = false + } + object XMLOptions { + def withStripComments(x: Boolean) = new XMLOptions { override val stripComments = x } + def withMinimizeTags(x: Boolean) = new XMLOptions { override val minimizeTags = x } + } /** trims an element - call this method, when you know that it is an * element (and not a text node) so you know that it will not be trimmed @@ -174,8 +187,9 @@ object Utility extends AnyRef with parsing.TokenTests * * @todo define a way to escape literal characters to &xx; references */ - def toXML(n: Node, stripComment: Boolean): String = - sbToString(toXML(n, TopScope, _, stripComment)) + def toXML(n: Node, _stripComments: Boolean): String = { + sbToString(toXML(n, TopScope, _)(XMLOptions.withStripComments(_stripComments))) + } /** * Appends a tree to the given stringbuffer within given namespace scope. @@ -185,31 +199,30 @@ object Utility extends AnyRef with parsing.TokenTests * @param sb stringbuffer to append to * @param stripComment if true, strip comments */ - def toXML(x: Node, pscope: NamespaceBinding, sb: StringBuilder, stripComment: Boolean) { - x match { - - case c: Comment if !stripComment => - c.buildString(sb) - - case x: SpecialNode => - x.buildString(sb) + def toXML(x: Node, pscope: NamespaceBinding, sb: StringBuilder, _stripComments: Boolean) { + toXML(x, pscope, sb)(XMLOptions.withStripComments(_stripComments)) + } - case g: Group => - for (c <- g.nodes) toXML(c, x.scope, sb, stripComment) + def toXML(x: Node, pscope: NamespaceBinding, sb: StringBuilder)(implicit config: XMLOptions) { + import config._ + x match { + case c: Comment if !stripComments => c buildString sb + case x: SpecialNode => x buildString sb + case g: Group => for (c <- g.nodes) toXML(c, x.scope, sb) case _ => // print tag with namespace declarations sb.append('<') x.nameToString(sb) if (x.attributes ne null) x.attributes.buildString(sb) x.scope.buildString(sb, pscope) - if (x.child.isEmpty) + if (x.child.isEmpty && minimizeTags) // no children, so use short form: <xyz .../> - sb.append("/>") + sb.append(" />") else { // children, so use long form: <xyz ...>...</xyz> sb.append('>') - sequenceToXML(x.child, x.scope, sb, stripComment) + sequenceToXML(x.child, x.scope, sb, stripComments) sb.append("</") x.nameToString(sb) sb.append('>') @@ -217,31 +230,33 @@ object Utility extends AnyRef with parsing.TokenTests } } + + /** * @param children ... * @param pscope ... * @param sb ... * @param stripComment ... */ - def sequenceToXML(children: Seq[Node], pscope: NamespaceBinding, - sb: StringBuilder, stripComment: Boolean) { - if (children.isEmpty) { - return - } else if (children forall { - case y: Atom[_] => !y.isInstanceOf[Text] - case _ => false - }) { // add space + def sequenceToXML(children: Seq[Node], pscope: NamespaceBinding, sb: StringBuilder, _stripComments: Boolean) { + sequenceToXML(children, pscope, sb)(XMLOptions.withStripComments(_stripComments)) + } + + def sequenceToXML(children: Seq[Node], pscope: NamespaceBinding, sb: StringBuilder)(implicit config: XMLOptions) { + import config._ + + if (children.isEmpty) return + else if (children forall isAtomAndNotText) { // add space val it = children.elements val f = it.next - toXML(f, pscope, sb, stripComment) + toXML(f, pscope, sb) while (it.hasNext) { val x = it.next sb.append(' ') - toXML(x, pscope, sb, stripComment) + toXML(x, pscope, sb) } - } else { - for (c <- children) toXML(c, pscope, sb, stripComment) } + else children foreach { toXML(_, pscope, sb) } } /** diff --git a/src/library/scala/xml/Xhtml.scala b/src/library/scala/xml/Xhtml.scala index 8438f91173..ec1790238f 100644 --- a/src/library/scala/xml/Xhtml.scala +++ b/src/library/scala/xml/Xhtml.scala @@ -3,7 +3,7 @@ package scala.xml import parsing.XhtmlEntities -import Utility.sbToString +import Utility.{ XMLOptions, sbToString, isAtomAndNotText } /* (c) David Pollak 2007 WorldWide Conferencing, LLC */ @@ -31,8 +31,9 @@ object Xhtml * * @param nodeSeq the node sequence */ - def toXhtml(n: Node, stripComment: Boolean, convertAmp: Boolean): String = - sbToString(toXhtml(n, TopScope, _, stripComment, convertAmp)) + def toXhtml(n: Node, _stripComments: Boolean, _convertAmp: Boolean): String = { + sbToString(toXhtml(n, TopScope, _, _stripComments, _convertAmp)) + } /** * Appends a tree to the given stringbuffer within given namespace scope. @@ -43,27 +44,36 @@ object Xhtml * @param stripComment if true, strip comments * @param convertAmp if true, decode entity references */ + def toXhtml(n: Node, pscope: NamespaceBinding, sb: StringBuilder, _stripComments: Boolean, _convertAmp: Boolean): String = { + implicit val config = new XMLOptions { + override val stripComments = _stripComments + override val decodeEntities = _convertAmp + } + sbToString(toXhtml(n, TopScope, _)) + } + def toXhtml( x: Node, pscope: NamespaceBinding, - sb: StringBuilder, - stripComment: Boolean, - convertAmp: Boolean): Unit = + sb: StringBuilder)(implicit config: XMLOptions): Unit = { + import config._ + def decode(er: EntityRef) = XhtmlEntities.entMap.get(er.entityName) match { case Some(chr) if chr.toInt >= 128 => sb.append(chr) case _ => er.buildString(sb) } def shortForm = + minimizeTags && (x.child == null || x.child.length == 0) && !(List("div", "script", "textarea") contains x.label) x match { - case c: Comment if !stripComment => c.buildString(sb) - case er: EntityRef if convertAmp => decode(er) - case x: SpecialNode => x.buildString(sb) - case g: Group => - g.nodes foreach { toXhtml(_, x.scope, sb, stripComment, convertAmp) } + case c: Comment if !stripComments => c buildString sb + case er: EntityRef if decodeEntities => decode(er) + case x: SpecialNode => x buildString sb + case g: Group => + g.nodes foreach { toXhtml(_, x.scope, sb) } case _ => sb.append('<') @@ -74,7 +84,7 @@ object Xhtml if (shortForm) sb.append(" />") else { sb.append('>') - sequenceToXML(x.child, x.scope, sb, stripComment, convertAmp) + sequenceToXML(x.child, x.scope, sb) sb.append("</") x.nameToString(sb) sb.append('>') @@ -89,17 +99,28 @@ object Xhtml children: Seq[Node], pscope: NamespaceBinding, sb: StringBuilder, - stripComment: Boolean, - convertAmp: Boolean): Unit = + _stripComments: Boolean, + _convertAmp: Boolean): Unit = + { + implicit val config = new XMLOptions { + override val stripComments = _stripComments + override val decodeEntities = _convertAmp + } + sequenceToXML(children, pscope, sb) + } + + def sequenceToXML( + children: Seq[Node], + pscope: NamespaceBinding, + sb: StringBuilder)(implicit config: XMLOptions): Unit = { - def isAtomAndNotText(x: Node) = x.isInstanceOf[Atom[_]] && !x.isInstanceOf[Text] val doSpaces = children forall isAtomAndNotText // interleave spaces for (c <- children.take(children.length - 1)) { - toXhtml(c, pscope, sb, stripComment, convertAmp) + toXhtml(c, pscope, sb) if (doSpaces) sb append ' ' } - toXhtml(children.last, pscope, sb, stripComment, convertAmp) + toXhtml(children.last, pscope, sb) } } |