~ubuntu-branches/debian/sid/scala/sid

« back to all changes in this revision

Viewing changes to src/library/scala/xml/Utility.scala

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg, Mehdi Dogguy, Lucas Satabin, Frank S. Thomas, Emmanuel Bourg
  • Date: 2015-06-05 23:52:59 UTC
  • mfrom: (1.2.11)
  • Revision ID: package-import@ubuntu.com-20150605235259-wk00vgk83dh8o19g
Tags: 2.10.5-1
* Team upload.

[ Mehdi Dogguy ]
* New upstream release (Closes: #744278).

[ Lucas Satabin ]
* Update patches
* Update the clean target
* Update paths of elements to install
* Update watch file

[ Frank S. Thomas ]
* Remove myself from Uploaders.

[ Emmanuel Bourg ]
* The package has been adopted by the Java Team (Closes: #754935)
* Patched the build to avoid downloading libraries from the Internet
* Replaced the minified JavaScript files with unobfuscated ones
* No longer build scala-partest.jar until diffutils is packaged or replaced
* debian/watch: Fixed the versions matched (x.y.z instead of x.y.z..z)
* debian/rules:
  - Added the missing get-orig-source target (Closes: #724704)
  - Improved the clean target
* debian/control:
  - Build depend on scala (>= 2.10) and bnd
  - Use canonical URLs for the Vcs-* fields
  - Standards-Version updated to 3.9.6 (no changes)
* Switch to debhelper level 9

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*                     __                                               *\
2
2
**     ________ ___   / /  ___     Scala API                            **
3
 
**    / __/ __// _ | / /  / _ |    (c) 2003-2011, LAMP/EPFL             **
 
3
**    / __/ __// _ | / /  / _ |    (c) 2003-2013, LAMP/EPFL             **
4
4
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
5
5
** /____/\___/_/ |_/____/_/ | |                                         **
6
6
**                          |/                                          **
7
7
\*                                                                      */
8
8
 
9
 
 
10
 
 
11
9
package scala.xml
12
10
 
13
 
import collection.mutable
14
 
import mutable.{ Set, HashSet }
 
11
import scala.collection.mutable
15
12
import parsing.XhtmlEntities
 
13
import scala.language.implicitConversions
16
14
 
17
15
/**
18
 
 * The <code>Utility</code> object provides utility functions for processing
19
 
 * instances of bound and not bound XML classes, as well as escaping text nodes.
 
16
 * The `Utility` object provides utility functions for processing instances
 
17
 * of bound and not bound XML classes, as well as escaping text nodes.
20
18
 *
21
19
 * @author Burak Emir
22
20
 */
23
 
object Utility extends AnyRef with parsing.TokenTests
24
 
{
 
21
object Utility extends AnyRef with parsing.TokenTests {
25
22
  final val SU = '\u001A'
26
23
 
 
24
  // [Martin] This looks dubious. We don't convert StringBuilders to
 
25
  // Strings anywhere else, why do it here?
27
26
  implicit def implicitSbToString(sb: StringBuilder) = sb.toString()
28
27
 
29
28
  // helper for the extremely oft-repeated sequence of creating a
35
34
  }
36
35
  private[xml] def isAtomAndNotText(x: Node) = x.isAtom && !x.isInstanceOf[Text]
37
36
 
38
 
  /** trims an element - call this method, when you know that it is an
 
37
  /** Trims an element - call this method, when you know that it is an
39
38
   *  element (and not a text node) so you know that it will not be trimmed
40
 
   *  away. With this assumption, the function can return a <code>Node</code>,
41
 
   *  rather than a <code>Seq[Node]</code>. If you don't know, call
42
 
   *  <code>trimProper</code> and account for the fact that you may get back
43
 
   *  an empty sequence of nodes.
 
39
   *  away. With this assumption, the function can return a `Node`, rather
 
40
   *  than a `Seq[Node]`. If you don't know, call `trimProper` and account
 
41
   *  for the fact that you may get back an empty sequence of nodes.
44
42
   *
45
 
   *  precondition: node is not a text node (it might be trimmed)
 
43
   *  Precondition: node is not a text node (it might be trimmed)
46
44
   */
47
45
  def trim(x: Node): Node = x match {
48
46
    case Elem(pre, lab, md, scp, child@_*) =>
49
47
      Elem(pre, lab, md, scp, (child flatMap trimProper):_*)
50
48
  }
51
49
 
52
 
  /** trim a child of an element. <code>Attribute</code> values and
53
 
   *  <code>Atom</code> nodes that are not <code>Text</code> nodes are unaffected.
 
50
  /** trim a child of an element. `Attribute` values and `Atom` nodes that
 
51
   *  are not `Text` nodes are unaffected.
54
52
   */
55
53
  def trimProper(x:Node): Seq[Node] = x match {
56
54
    case Elem(pre,lab,md,scp,child@_*) =>
60
58
    case _ =>
61
59
      x
62
60
  }
 
61
 
63
62
  /** returns a sorted attribute list */
64
63
  def sort(md: MetaData): MetaData = if((md eq Null) || (md.next eq Null)) md else {
65
64
    val key = md.key
66
65
    val smaller = sort(md.filter { m => m.key < key })
67
66
    val greater = sort(md.filter { m => m.key > key })
68
 
    smaller.append( Null ).append(md.copy ( greater ))
 
67
    smaller.foldRight (md copy greater) ((x, xs) => x copy xs)
69
68
  }
70
69
 
71
 
  /** returns the node with its attribute list sorted alphabetically (prefixes are ignored) */
 
70
  /** Return the node with its attribute list sorted alphabetically
 
71
   *  (prefixes are ignored) */
72
72
  def sort(n:Node): Node = n match {
73
 
          case Elem(pre,lab,md,scp,child@_*) =>
74
 
                  Elem(pre,lab,sort(md),scp, (child map sort):_*)
75
 
          case _ => n
 
73
        case Elem(pre,lab,md,scp,child@_*) =>
 
74
      Elem(pre,lab,sort(md),scp, (child map sort):_*)
 
75
    case _ => n
76
76
  }
77
77
 
78
78
  /**
79
79
   * Escapes the characters &lt; &gt; &amp; and &quot; from string.
80
 
   *
81
 
   * @param text ...
82
 
   * @return     ...
83
80
   */
84
81
  final def escape(text: String): String = sbToString(escape(text, _))
85
82
 
101
98
  import Escapes.{ escMap, unescMap }
102
99
 
103
100
  /**
104
 
   * Appends escaped string to <code>s</code>.
105
 
   *
106
 
   * @param text ...
107
 
   * @param s    ...
108
 
   * @return     ...
 
101
   * Appends escaped string to `s`.
109
102
   */
110
103
  final def escape(text: String, s: StringBuilder): StringBuilder = {
111
104
    // Implemented per XML spec:
132
125
  }
133
126
 
134
127
  /**
135
 
   * Appends unescaped string to <code>s</code>, amp becomes &amp;
136
 
   * lt becomes &lt; etc..
 
128
   * Appends unescaped string to `s`, `amp` becomes `&amp;`,
 
129
   * `lt` becomes `&lt;` etc..
137
130
   *
138
 
   * @param ref ...
139
 
   * @param s   ...
140
 
   * @return    <code>null</code> if <code>ref</code> was not a predefined
141
 
   *            entity.
 
131
   * @return    `'''null'''` if `ref` was not a predefined entity.
142
132
   */
143
133
  final def unescape(ref: String, s: StringBuilder): StringBuilder =
144
 
    (unescMap get ref) map (s append _) orNull
 
134
    ((unescMap get ref) map (s append _)).orNull
145
135
 
146
136
  /**
147
137
   * Returns a set of all namespaces used in a sequence of nodes
148
138
   * and all their descendants, including the empty namespaces.
149
 
   *
150
 
   * @param nodes ...
151
 
   * @return      ...
152
139
   */
153
140
  def collectNamespaces(nodes: Seq[Node]): mutable.Set[String] =
154
 
    nodes.foldLeft(new HashSet[String]) { (set, x) => collectNamespaces(x, set) ; set }
 
141
    nodes.foldLeft(new mutable.HashSet[String]) { (set, x) => collectNamespaces(x, set) ; set }
155
142
 
156
143
  /**
157
144
   * Adds all namespaces in node to set.
158
 
   *
159
 
   * @param n   ...
160
 
   * @param set ...
161
145
   */
162
146
  def collectNamespaces(n: Node, set: mutable.Set[String]) {
163
147
    if (n.doCollectNamespaces) {
185
169
  //   sb.toString()
186
170
  // }
187
171
 
 
172
  /**
 
173
   * Serialize the provided Node to the provided StringBuilder.
 
174
   * <p/>
 
175
   * Note that calling this source-compatible method will result in the same old, arguably almost universally unwanted,
 
176
   * behaviour.
 
177
   */
 
178
  @deprecated("Please use `serialize` instead and specify a `minimizeTags` parameter", "2.10.0")
188
179
  def toXML(
189
180
    x: Node,
190
181
    pscope: NamespaceBinding = TopScope,
194
185
    preserveWhitespace: Boolean = false,
195
186
    minimizeTags: Boolean = false): StringBuilder =
196
187
  {
 
188
    serialize(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, if (minimizeTags) MinimizeMode.Always else MinimizeMode.Never)
 
189
  }
 
190
 
 
191
  /**
 
192
   * Serialize an XML Node to a StringBuilder.
 
193
   *
 
194
   * This is essentially a minor rework of `toXML` that can't have the same name due to an unfortunate
 
195
   * combination of named/default arguments and overloading.
 
196
   *
 
197
   * @todo use a Writer instead
 
198
   */
 
199
  def serialize(
 
200
    x: Node,
 
201
    pscope: NamespaceBinding = TopScope,
 
202
    sb: StringBuilder = new StringBuilder,
 
203
    stripComments: Boolean = false,
 
204
    decodeEntities: Boolean = true,
 
205
    preserveWhitespace: Boolean = false,
 
206
    minimizeTags: MinimizeMode.Value = MinimizeMode.Default): StringBuilder =
 
207
  {
197
208
    x match {
198
 
      case c: Comment => if (!stripComments) c buildString sb else sb
199
 
      case x: SpecialNode => x buildString sb
200
 
      case g: Group =>
201
 
        g.nodes foreach {toXML(_, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)}
202
 
        sb
203
 
      case _  =>
 
209
      case c: Comment if !stripComments => c buildString sb
 
210
      case s: SpecialNode               => s buildString sb
 
211
      case g: Group                     => for (c <- g.nodes) serialize(c, g.scope, sb, minimizeTags = minimizeTags) ; sb
 
212
      case el: Elem  =>
204
213
        // print tag with namespace declarations
205
214
        sb.append('<')
206
 
        x.nameToString(sb)
207
 
        if (x.attributes ne null) x.attributes.buildString(sb)
208
 
        x.scope.buildString(sb, pscope)
209
 
        if (x.child.isEmpty && minimizeTags) {
 
215
        el.nameToString(sb)
 
216
        if (el.attributes ne null) el.attributes.buildString(sb)
 
217
        el.scope.buildString(sb, pscope)
 
218
        if (el.child.isEmpty &&
 
219
                (minimizeTags == MinimizeMode.Always ||
 
220
                (minimizeTags == MinimizeMode.Default && el.minimizeEmpty)))
 
221
        {
210
222
          // no children, so use short form: <xyz .../>
211
 
          sb.append(" />")
 
223
          sb.append("/>")
212
224
        } else {
213
225
          // children, so use long form: <xyz ...>...</xyz>
214
226
          sb.append('>')
215
 
          sequenceToXML(x.child, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
 
227
          sequenceToXML(el.child, el.scope, sb, stripComments)
216
228
          sb.append("</")
217
 
          x.nameToString(sb)
 
229
          el.nameToString(sb)
218
230
          sb.append('>')
219
231
        }
 
232
      case _ => throw new IllegalArgumentException("Don't know how to serialize a " + x.getClass.getName)
220
233
    }
221
234
  }
222
235
 
227
240
    stripComments: Boolean = false,
228
241
    decodeEntities: Boolean = true,
229
242
    preserveWhitespace: Boolean = false,
230
 
    minimizeTags: Boolean = false): Unit =
 
243
    minimizeTags: MinimizeMode.Value = MinimizeMode.Default): Unit =
231
244
  {
232
245
    if (children.isEmpty) return
233
246
    else if (children forall isAtomAndNotText) { // add space
234
247
      val it = children.iterator
235
248
      val f = it.next
236
 
      toXML(f, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
 
249
      serialize(f, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
237
250
      while (it.hasNext) {
238
251
        val x = it.next
239
252
        sb.append(' ')
240
 
        toXML(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
 
253
        serialize(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)
241
254
      }
242
255
    }
243
 
    else children foreach { toXML(_, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) }
 
256
    else children foreach { serialize(_, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) }
244
257
  }
245
258
 
246
259
  /**
247
260
   * Returns prefix of qualified name if any.
248
 
   *
249
 
   * @param name ...
250
 
   * @return     ...
251
261
   */
252
262
  final def prefix(name: String): Option[String] = (name indexOf ':') match {
253
263
    case -1   => None
256
266
 
257
267
  /**
258
268
   * Returns a hashcode for the given constituents of a node
259
 
   *
260
 
   * @param uri
261
 
   * @param label
262
 
   * @param attribHashCode
263
 
   * @param children
264
269
   */
265
 
  def hashCode(pre: String, label: String, attribHashCode: Int, scpeHash: Int, children: Seq[Node]) = {
266
 
    val h = new util.MurmurHash[Node](pre.##)
267
 
    h.append(label.##)
268
 
    h.append(attribHashCode)
269
 
    h.append(scpeHash)
270
 
    children.foreach(h)
271
 
    h.hash
272
 
  }
 
270
  def hashCode(pre: String, label: String, attribHashCode: Int, scpeHash: Int, children: Seq[Node]) =
 
271
    scala.util.hashing.MurmurHash3.orderedHash(label +: attribHashCode +: scpeHash +: children, pre.##)
273
272
 
274
273
  def appendQuoted(s: String): String = sbToString(appendQuoted(s, _))
275
274
 
276
275
  /**
277
 
   * Appends &quot;s&quot; if string <code>s</code> does not contain &quot;,
 
276
   * Appends &quot;s&quot; if string `s` does not contain &quot;,
278
277
   * &apos;s&apos; otherwise.
279
 
   *
280
 
   * @param s  ...
281
 
   * @param sb ...
282
 
   * @return   ...
283
278
   */
284
279
  def appendQuoted(s: String, sb: StringBuilder) = {
285
280
    val ch = if (s contains '"') '\'' else '"'
288
283
 
289
284
  /**
290
285
   * Appends &quot;s&quot; and escapes and &quot; i s with \&quot;
291
 
   *
292
 
   * @param s  ...
293
 
   * @param sb ...
294
 
   * @return   ...
295
286
   */
296
287
  def appendEscapedQuoted(s: String, sb: StringBuilder): StringBuilder = {
297
288
    sb.append('"')
302
293
    sb.append('"')
303
294
  }
304
295
 
305
 
  /**
306
 
   * @param s     ...
307
 
   * @param index ...
308
 
   * @return      ...
309
 
   */
310
296
  def getName(s: String, index: Int): String = {
311
297
    if (index >= s.length) null
312
298
    else {
317
303
  }
318
304
 
319
305
  /**
320
 
   * Returns <code>null</code> if the value is a correct attribute value,
 
306
   * Returns `'''null'''` if the value is a correct attribute value,
321
307
   * error message if it isn't.
322
 
   *
323
 
   * @param value ...
324
 
   * @return      ...
325
308
   */
326
309
  def checkAttributeValue(value: String): String = {
327
310
    var i = 0
343
326
    null
344
327
  }
345
328
 
346
 
  /**
347
 
   * new
348
 
   *
349
 
   * @param value ...
350
 
   * @return      ...
351
 
   */
352
329
  def parseAttributeValue(value: String): Seq[Node] = {
353
330
    val sb  = new StringBuilder
354
331
    var rfb: StringBuilder = null
374
351
            c = it.next
375
352
          }
376
353
          val ref = rfb.toString()
377
 
          rfb.setLength(0)
 
354
          rfb.clear()
378
355
          unescape(ref,sb) match {
379
356
            case null =>
380
 
              if (sb.length > 0) {          // flush buffer
 
357
              if (sb.length > 0) {  // flush buffer
381
358
                nb += Text(sb.toString())
382
 
                sb.setLength(0)
 
359
                sb.clear()
383
360
              }
384
 
              nb += EntityRef(sb.toString()) // add entityref
 
361
              nb += EntityRef(ref) // add entityref
385
362
            case _ =>
386
363
          }
387
364
        }
399
376
  }
400
377
 
401
378
  /**
402
 
   * <pre>
 
379
   * {{{
403
380
   *   CharRef ::= "&amp;#" '0'..'9' {'0'..'9'} ";"
404
381
   *             | "&amp;#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";"
405
 
   * </pre>
406
 
   * <p>
407
 
   *   see [66]
408
 
   * <p>
409
 
   *
410
 
   * @param ch                ...
411
 
   * @param nextch            ...
412
 
   * @param reportSyntaxError ...
413
 
   * @return                  ...
 
382
   * }}}
 
383
   * See [66]
414
384
   */
415
385
  def parseCharRef(ch: () => Char, nextch: () => Unit, reportSyntaxError: String => Unit, reportTruncatedError: String => Unit): String = {
416
386
    val hex  = (ch() == 'x') && { nextch(); true }