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>></d>) res21: String = Node d with entity: gt
![]() | Specyfikacja języka Scala opisuje wzorce XML w punkcie 10.2. |
Plik PatternMatchXML1.scala:
import scala.xml._
def f(node: Node) = node match {
case <a/> => "Empty node a" 
