Scala: синтаксический анализ атрибутов XML

Я пытаюсь разобрать rss-канал, который выглядит так для атрибута "date":

<rss version="2.0">
<channel>
    <item>
        <y:c date="AA"></y:c>
    </item>
</channel>
</rss>

Я попробовал несколько разных версий: (rssFeed содержит данные RSS)

println(((rssFeed \\ "channel" \\ "item" \ "y:c" \"date").toString))

Но ничего не работает. Что мне не хватает?

Любая помощь будет действительно оценена!

Ответ 1

"y" в <y:c является префиксом пространства имен. Это не часть имени. Кроме того, атрибуты называются "@". Попробуйте следующее:

println(((rssFeed \\ "channel" \\ "item" \ "c" \ "@date").toString))

Ответ 2

Атрибуты извлекаются с помощью селектора "@attrName". Таким образом, ваш селектор должен быть примерно таким:

println((rssFeed \\ "channel" \\ "item" \ "c" \ "@date").text)

Ответ 3

Также подумайте о разнице между \ и \\. \\ ищет потомка, а не только ребенка, как это (обратите внимание, что он перескакивает с канала на c, без элемента):

scala> (rssFeed \\ "channel" \\ "c" \ "@date").text
res20: String = AA

Или такого рода вещи, если вы просто хотите, чтобы все <c> элементов и не заботятся о своих родителях:

scala> (rssFeed \\ "c" \ "@date").text            
res24: String = AA

И это указывает точный путь:

scala> (rssFeed \ "channel" \ "item" \ "c" \ "@date").text
res25: String = AA

Ответ 4

Подумайте также об использовании понятий последовательностей. Они полезны для работы с XML, особенно если вам нужны сложные условия.

Для простого случая:

for {
  c <- rssFeed \\ "@date"
} yield c

Дает вам атрибут даты из всего в rssFeed.

Но если вам нужно что-то более сложное:

val rssFeed = <rss version="2.0">
                <channel>
                  <item>
                    <y:c date="AA"></y:c>
                    <y:c date="AB"></y:c>
                    <y:c date="AC"></y:c>
                  </item>
                </channel>
              </rss>

val sep = "\n----\n"

for {
  channel <- rssFeed \ "channel"
  item <- channel \ "item"
  y <- item \ "c"
  date <- y \ "@date" if (date text).equals("AA")
} yield {
  val s = List(channel, item, y, date).mkString(sep)
  println(s)
}

Дает вам:

    <channel>
                        <item>
                          <y:c date="AA"></y:c>
                          <y:c date="AB"></y:c>
                          <y:c date="AC"></y:c>
                        </item>
                      </channel>
    ----
    <item>
                          <y:c date="AA"></y:c>
                          <y:c date="AB"></y:c>
                          <y:c date="AC"></y:c>
                        </item>
    ----
    <y:c date="AA"></y:c>
    ----
    AA