Выполнение сложных запросов XPath в Scala
Какой самый простой API для использования в scala для выполнения следующих запросов XPath в документе?
//s:Annotation[@type='attitude']/s:Content/s:Parameter[@role='type' and not(text())]
//s:Annotation[s:Content/s:Parameter[@role='id' and not(text())]]/@type
(s
определяется как псевдоним для определенного пространства имен)
Единственная документация, которую я могу найти в библиотеках XML scala, не содержит информации о выполнении сложных реальных запросов XPath.
Мне нравилось JDOM для этой цели (на Java), но поскольку JDOM не поддерживает дженерики, это будет болезненно для работы с Scala. (Другие библиотеки XML для Java, как правило, еще более болезненны на Java, но я признаю, что я не очень хорошо знаю ландшафт.)
Ответы
Ответ 1
Я думаю, что я пойду с легким сутенерством XOM. Немного стыдно, что авторы XOM решили не подвергать коллекциям дочерние узлы и т.п., Но у них было больше работы и меньше преимуществ для этого на Java, чем в Scala. (И это хорошо спроектированная библиотека.)
РЕДАКТИРОВАТЬ: Я закончил сутенерство JDOM, потому что XOM не компилирует запросы XPath раньше времени. Поскольку большинство моих усилий было направлено на XPath на этот раз, я смог придумать хорошую модель, которая обошла бы большинство проблем с генериками. Не должно быть слишком сложно найти разумные обобщенные версии методов getChildren
и getAttributes
и getAdditionalNamespaces
в org.jdom.Element
(путем сутенерства библиотеки с новыми методами, которые немного изменили имена). Я не знаю, t думаю, что есть исправление для getContent
, и я не уверен в getDescendants
.
Ответ 2
//s:Annotation[@type='attitude']/s:Content/s:Parameter[@role='type' and not(text())]
Ну, я не понимаю нотацию s:
и не могу найти ее в спецификации XPath. Однако, игнорируя это, было бы так:
(
(xml
\\ "Annotation"
filter (_ \ "@type" contains Text("x"))
)
\ "Content"
\ "Parameter"
filter (el => (el \ "@type" contains Text("type")) && el.isInstanceOf[Text])
)
Обратите внимание на необходимость скобки из-за более высокого приоритета \
над filter
. Я изменил форматирование на многострочное выражение, поскольку эквивалент Scala просто слишком подробен для одной строки.
Я не могу ответить об пространствах имен. Не знаю, как работать с ними при поиске, если это возможно. В документах упоминается @{uri}attribute
для префиксных атрибутов, а не о каких-либо элементах префикса. Кроме того, обратите внимание, что вам необходимо передать uri, который разрешает пространство имен, которое вы хотите, поскольку литералы в пространстве имен не поддерживаются.
Ответ 3
Scales Xml добавляет как полную оценку XPath на основе всей строки, так и внутреннюю DSL, предоставляющую достаточно полный охват для запросов
Ответ 4
Я предполагаю, что когда scalaxmljaxen является зрелым, мы сможем надежно сделать это на scala встроенных XML-классах.
Ответ 5
Я бы предложил использовать kantan.xpath:
import kantan.xpath._
import kantan.xpath.implicits._
input.evalXPath[List[String]](xp"/annotation[@type='attitude']/content/parameter[@role='type' and not(text())]/@value")
Это дает:
res1: kantan.xpath.XPathResult[List[String]] = Success(List(foobar))