Соответствие шаблону XML Scala, элемент верхнего уровня - PullRequest
2 голосов
/ 08 апреля 2019

Рассмотрим следующий узел XML:

 <Interval>
   <P v="1"/>
   <Q v="0.0"/>
  </Interval>

Как правильно сопоставить шаблон с элементом верхнего уровня в Scala? Я ожидаю, что следующее будет работать, но это не так:

def visit(node:Node):String = {
    node match {
        case p @ <P/> => (p \ "@v") text
        case q @ <Q/> => (q \ "@v") text
        case <Interval> @ children:_* </Interval> => "parent"
    }
}

Ответы [ 2 ]

2 голосов
/ 09 апреля 2019

Когда вы создаете XML-литерал в Scala, переменная, которую вы ему присваиваете , равна элементу верхнего уровня.

val node: scala.xml.Elem =
  <Interval>
   <P v="1"/>
   <Q v="0.0"/>
  </Interval> 

Чтобы соответствовать элементу верхнего уровня, здесь Interval или любой элемент Interval, имеющий дочерние элементы, такие как ваш пример, вы можете использовать фигурные скобки для соответствия дочерним элементам.

node match {
  case <Interval>{ children @_* }</Interval> => children.collect {
    case p @ <P/> => p \@ "v"
    case q @ <Q/> => q \@ "v"
  }
}

Результат:

Seq("1", "0.0")

Есливы не знакомы с collect, он позволяет вам предоставлять частичную функцию (читаемую как «сопоставление с образцом») и игнорировать случаи, которые в противном случае потерпели бы неудачу из-за ошибки сопоставления.

0 голосов
/ 08 апреля 2019

Это выражение в скале:

<Interval>
 <P v="1"/>
 <Q v="0.0"/>
</Interval>

определенно вернет scala.xml.Node в scala, но сначала scala.xml.Elem. Вы можете сопоставить образец с ним следующим образом:

import scala.xml.Elem

def visit(elem: Elem) = {
    elem match {
        case e@Elem(_, "Interval",_, _, _*) => "identified!"
    }
}

Или вы можете также сопоставить с шаблоном на child, потому что вы сопоставляете шаблон с объектом n типа Elem, как Elem(n.prefix, n.label, n.attributes, n.scope, n.child), и здесь child элементы (это Seq) сопоставляются с каждым Остальные элементы шаблона:

def visit(elem: Elem) = {
    elem match {
        case Elem(_, "Interval",_, _, emptyElem, nodeIWant@(<P/>), _*) =>
        (nodeIWant \ "@v").text
    }
}

которые возвращают 1 здесь, например.

Надеюсь, это поможет.

...