summaryrefslogtreecommitdiff
path: root/sources/scala/xml/NodeSeq.scala
blob: 56ab68a13081e52fb3c968cf4ece03f1187537c1 (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
/*                     __                                               *\
**     ________ ___   / /  ___     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;
  }
  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] {

  def theSeq: Seq[Node];
  def length = theSeq.length;
  def elements = theSeq.elements ;
  def apply( i:int ) = theSeq.apply( i );

  /** structural equality */
  override def equals( x:Any ) = x match {
    case z:Node      => ( length == 1 ) && z == apply( 0 )
    case z:Seq[Node] => sameElements( 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 = that match {
    case "_" => for( val x <- this;
                     val y <- new NodeSeq { val theSeq = x.child; })
                yield y
    case _   => for( val x <- this;
                     val y <- new NodeSeq { val theSeq = x.child; };
                     y.label == that )
                yield { y }
  }

  /** 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 <- new NodeSeq { val theSeq = x.descendant_or_self })
                  yield { y }
      case _ => for( val x <- this;
                     val y <- new NodeSeq { val theSeq =  x.descendant_or_self  };
                     y.label == that)
                  yield { y }
  }

  override def toString():String = theSeq.elements.foldLeft ("") {
    (s:String,x:Node) => s + x.toString()
  }

  private var _asList:List[Node] = null;
  def asList = {
    if (_asList == null ) _asList = elements.toList;
    _asList
  }

  def map( f:Node => Node ):NodeSeq = {
    new NodeSeq{ final def theSeq = NodeSeq.this.asList map f }
  }

  def flatMap( f:Node => NodeSeq ):NodeSeq = {
    new NodeSeq{ final def theSeq = NodeSeq.this.asList flatMap { x => f(x).asList }}
  }

  def filter( f:Node => boolean ):NodeSeq = {
    new NodeSeq{ val theSeq = NodeSeq.this.asList filter f  }
  }

}