blob: 84d37d57905b23823183211a5dda8ad8c4b56d18 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
** $Id$
\* */
package scala.xml ;
object NodeSeq {
final val Empty = new NodeSeq { def theSeq = Nil; }
def fromSeq(s:Seq[Node]):NodeSeq = new NodeSeq {
def theSeq = s;
}
implicit def view(s:Seq[Node]):NodeSeq = fromSeq(s);
}
/** a wrapper around Seq[Node] that adds XPath and comprehension methods */
abstract class NodeSeq extends Seq[Node] {
import NodeSeq.view; // import view magic for NodeSeq wrappers
def theSeq: Seq[Node];
def length = theSeq.length;
def elements = theSeq.elements ;
def apply(i: int ): Node = theSeq.apply( i );
def apply(f: Node => Boolean): NodeSeq = filter(f);
/** structural equality */
override def equals(x: Any) = x match {
case z:Node => (length == 1) && z == apply(0)
case z:Seq[Node] => sameElements( z )
case z:String => text == z
case _ => false;
}
/** projection function. Similar to XPath, use this \ "foo" to get a list
* of all elements of this sequence that are labelled with "foo".
* Use \ "_" as a wildcard. The document order is preserved.
*/
def \(that: String):NodeSeq = {
var res: NodeSeq = NodeSeq.Empty;
that match {
case "_" =>
res = for( val x <- this; val y <- x.child: NodeSeq) yield { y }
case _ if (that.charAt(0) == '@') && (this.length == 1) =>
val k = that.substring(1);
val y = this(0);
val v = y.attribute(k);
if( v != null ) {
res = NodeSeq.fromSeq(Seq.single(Text(v)));
}
case _ =>
res = for( val x <- this; val y <- x.child: NodeSeq; y.label == that )
yield { y }
}
res
}
/** projection function. Similar to XPath, use this \\ 'foo to get a list
* of all elements of this sequence that are labelled with "foo".
* Use \ "_" as a wildcard. The document order is preserved.
*/
def \\ ( that:String ): NodeSeq = that match {
case "_" => for( val x <- this;
val y <- x.descendant_or_self: NodeSeq )
yield { y }
case _ if that.charAt(0) == '@' =>
val attrib = that.substring(1);
(for(val x <- this;
val y <- x.descendant_or_self: NodeSeq;
val z <- y \ that)
yield { z }):NodeSeq
case _ => for( val x <- this;
val y <- x.descendant_or_self: NodeSeq;
y.label == that)
yield { y }
}
override def toString():String = theSeq.elements.foldLeft ("") {
(s:String,x:Node) => s + x.toString()
}
def asList = elements.toList;
def map(f: Node => Node): NodeSeq = { val x = asList map f; x }
def flatMap(f:Node => NodeSeq): NodeSeq = { val y = asList flatMap { x => f(x).asList }; y }
def filter(f:Node => Boolean): NodeSeq = { val x = asList filter f; x }
def text: String = {
val sb = new StringBuffer();
val it = elements;
while(it.hasNext) {
sb.append(it.next.text);
}
sb.toString();
}
}
|