21.5. Wzorce XML

Specjalna składnia XML jest również dostępna przy dopasowywaniu wzorców. W pliku PatternMatchXML1.scala znajduje się metoda f zawierająca wyrażenie match z kilkoma wzorcami dopasowującymi różne elementy XML.

Plik PatternMatchXML1.scala:
import scala.xml._
def f(node: Node) = node match {
  case <a/> => "Empty node a" 
  case <b></b> => "Empty node b" 
  case <c>{_}</c> => "Node c with a child" 
  case <d>{x}</d> => "Node d with the following child: "+x 
  case <e>{x @ _*}</e> => "Node e with the following content "+x 
  case _ => "not matched"
}

Wzorce z wierszy oraz dopasowują puste elementy a i b. Elementy mające jakąś zawartość nie są dopasowywane.

scala> :load PatternMatchXML1.scala
Loading PatternMatchXML1.scala...
import scala.xml._
f: (node: scala.xml.Node)String

scala> f(<a/>)
res0: String = Empty node a

scala> f(<b id="bb"/>)
res1: String = Empty node b

scala> f(<a><b/></a>)
res2: String = not matched

scala> f(<b>abc</b>)
res3: String = not matched

Wzorzec z wiersza dopasowuje element c, mający pojedynczy węzeł będący dzieckiem.

scala> f(<c/>) 
res4: String = not matched

scala> f(<c>abc</c>)
res5: String = Node c with a child

scala> f(<c><b/></c>)
res6: String = Node c with a child

scala> f(<c><b>123</b></c>)
res7: String = Node c with a child

scala> f(<c>abc<a/></c>) 
res8: String = not matched

Węzeł dopasowywany w wierszu nie został dopasowany, ponieważ nie posiada żadnego dziecka. Węzeł dopasowywany w wierszu nie został dopasowany, ponieważ posiada więcej niż jedno dziecko. Wzorzec z wiersza dopasowuje element d mający pojedynczy węzeł będący dzieckiem, a dodatkowo wiąże dopasowany węzeł-dziecko ze zmienną x.

scala> f(<d>abc</d>)
res9: String = Node d with the following child: abc

scala> f(<d><b/></d>)
res10: String = Node d with the following child: <b/>

scala> f(<d><b>123</b></d>)
res11: String = Node d with the following child: <b>123</b>

Wzorzec z wiersza dopasowuje element e, a dodatkowo wiąże dopasowane węzły, będące dziećmi, ze zmienną x.

scala> f(<e/>)
res12: String = Node e with the following content WrappedArray()

scala> f(<e>abc</e>)
res13: String = Node e with the following content ArrayBuffer(abc)

scala> f(<e><b/></e>)
res14: String = Node e with the following content ArrayBuffer(<b/>)

scala> f(<e><b>123</b></e>)
res15: String = Node e with the following content ArrayBuffer(<b>123</b>)

scala> f(<e>abc<a/></e>)
res16: String = Node e with the following content ArrayBuffer(abc, <a/>)

W przypadku użycia wzorca _* do dopasowania zawartości elementu, dopasowanie następuje niezależnie od liczby dzieci węzła. Wszystkie dopasowywane elementy udało się dopasować.

Nie dla wszystkich rodzajów węzłów XML, które mogą być utworzone w programach języka Scala za pomocą specjalnej składni, można za pomocą takiej specjalnej składni utworzyć wzorce. W poniższych definicjach metod próby utworzenia wzorców zawierających atrybut (metoda f1), komentarz (metoda f2), instrukcję przetwarzania (metoda f3) i sekcję CDATA (metoda f4) nie udają się.

scala> import scala.xml._
import scala.xml._

scala> def f1(n: Node) = n match { case <b id="c"></b> => }
<console>:1: error: in XML literal: '>' expected instead of 'i'
def f1(n: Node) = n match { case <b id="c"></b> => }
                                    ^

scala> def f2(n: Node) = n match { case <b><!-- comment --></b> => }
<console>:1: error: in XML literal: name expected, but char '!' cannot start a name
def f2(n: Node) = n match { case <b><!-- comment --></b> => }
                                     ^
<console>:1: error: in XML literal: '>' expected instead of '-'
def f2(n: Node) = n match { case <b><!-- comment --></b> => }
                                      ^
<console>:1: error: in XML literal: expected closing tag of
def f2(n: Node) = n match { case <b><!-- comment --></b> => }
                                                       ^

scala> def f3(n: Node) = n match { case <b><?p ?></b> => }
<console>:1: error: in XML literal: name expected, but char '?' cannot start a name
def f3(n: Node) = n match { case <b><?p ?></b> => }
                                     ^
<console>:1: error: in XML literal: '>' expected instead of 'p'
def f3(n: Node) = n match { case <b><?p ?></b> => }
                                      ^
<console>:1: error: in XML literal: expected closing tag of
def f3(n: Node) = n match { case <b><?p ?></b> => }
                                             ^

scala> def f4(n: Node) = n match { case <b><![CDATA[x]]></b> => }
<console>:1: error: in XML literal: name expected, but char '!' cannot start a name
def f4(n: Node) = n match { case <b><![CDATA[x]]></b> => }
                                     ^
<console>:1: error: in XML literal: '>' expected instead of '['
def f4(n: Node) = n match { case <b><![CDATA[x]]></b> => }
                                      ^
<console>:1: error: in XML literal: expected closing tag of
def f4(n: Node) = n match { case <b><![CDATA[x]]></b> => }
                                                    ^

W celu dopasowania tych elementów XML, dla których nie można utworzyć wzorca za pomocą specjalnej składni, można użyć zwykłej składni dopasowania wzorców. Oczywiście dotyczy to również tych elementów XML, dla których da się utworzyć wzorce przy pomocy specjalnej składni. Można również mieszać wzorce utworzone za pomocą specjalnej składni XML ze zwykłymi wzorcami. Metoda g zdefiniowana w pliku PatternMatchXML2.scala dopasowuje różne rodzaje elementów XML.

Plik PatternMatchXML2.scala:
import scala.xml._
def g(node: Node) = node match {
  case Elem(_,"a",_,_) => "Empty node a"
  case Elem(_,"b",_,_,Text(t)) => "Element b with a text node: "+t
  case Comment(x) => "Comment: "+x
  case ProcInstr("p",_) => "Processing instruction p"
  case <d>{ EntityRef(x) }</d> => "Node d with entity: "+x
}

Wzorce z metody g dopasowują kolejno: pusty węzeł a, węzeł b z dzieckiem w postaci węzła tekstowego, komentarz, instrukcję przetwarzania p oraz węzeł d zawierajacy jednostkę.

scala> :load PatternMatchXML2.scala
Loading PatternMatchXML2.scala...
import scala.xml._
g: (node: scala.xml.Node)String

scala> g(<a/>)
res17: String = Empty node a

scala> g(<b>abcd</b>)
res18: String = Element b with a text node: abcd

scala> g(<!-- a comment -->)
res19: String = "Comment:  a comment "

scala> g(<?p abc?>)
res20: String = Processing instruction p

scala> g(<d>&gt;</d>)
res21: String = Node d with entity: gt

Specyfikacja języka Scala opisuje wzorce XML w punkcie 10.2.

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.