Как пройти один дочерний узел, используя scala.xml.Node - PullRequest
2 голосов
/ 20 января 2011

Расширяя вопрос, который я задавал ранее о том, как перебрать коллекцию узлов в scala.xml. Узел найден здесь

Я хотел сделать еще один шаг и спросить, какЯ мог бы посмотреть на предыдущего потомка внутри рекурсивной функции, чтобы получить значение, как только я столкнулся с конкретной ситуацией

Например (разметка здесь)

<html>
    <head class="foo">
        <title>Welcome</title>
    </head>
    <body>
        <div>
            <p>Foo</p>
        </div>
    </body>
</html>

С моей текущей реализацией (спасибо @ knut-arne-vedaa )

def processNode(node: Node) {
  if (node.isInstanceOf[Text]) {
      if (node.text.contains("Welcome"))
      {
        //then inside here I want to go up to the prev element (head) and pull the class 
      }
    }
  node.child foreach processNode
}

Я хочу добавить еще одно условие для получения текста "foo" из секции класса

Любая идеячто я мог бы добавить внутри этого оператора if, чтобы получить это значение напрямую?Кроме того, как я могу вернуть значение String из этого FX?разрыв с простой обратной линией или?

Ответы [ 3 ]

4 голосов
/ 20 января 2011

Обратите внимание, что родительский узел узла Text в вашем примере на самом деле является узлом .

Поскольку узлы не имеют ссылок на своих родителей, один из способов получить к ним доступ - просто передать их с собой при ходьбе по дереву, например:

def processNode(node: Node, parent: Option[Node]) {
  if (node.isInstanceOf[Text]) {
      if (node.text.contains("Welcome"))
      {
        println("Node: " + node)
        println("Parent: " + parent.getOrElse("[toplevel]"))
      }
    }
  node.child foreach { n: Node => processNode(n, Some(node)) }
}
processNode(xml, None)

Конечно, это становится громоздким, когда вы хотите взобраться на дерево на произвольный уровень. Один из подходов к этому - заключить ваши узлы в SuperNode, который имеет необязательную родительскую ссылку.

case class SuperNode(current: Node, parent: Option[SuperNode] = None)

Для удобства создайте неявную функцию для преобразования узлов в SuperNodes в случае отсутствия по умолчанию родительского элемента.

implicit def nodeMakeSuper(n: Node) = SuperNode(n)

Теперь вы можете перемещаться вверх по дереву произвольное количество раз, например:

def processNode(node: SuperNode) {
  node.current match {
      case n @ Text(t) if t.contains("Welcome") => {
          println("Node: " + n)
          node.parent match {
              case Some(p) => {
                  println("Parent: " + p.current)
                  p.parent match {
                      case Some(gp) => println("GrandParent: " + gp.current)
                      case None => println("No grandparent!")
                  }
              }
              case None => println("No parent!")
          }

      }
      case _ => // these aren't the droids you're looking for
  }
  node.current.child foreach { child: Node => processNode(SuperNode(child, Some(node))) }
}
2 голосов
/ 21 января 2011

Если вы продолжаете идти в этом направлении, вы должны использовать XML Zipper .Я думаю, что Scalaz имеет его (он есть, но я не уверен, что вы можете использовать его с XML).

1 голос
/ 21 января 2011

Если вы хотите что-то сделать со значением only , если оно находится внутри узла с определенным атрибутом, вы можете сделать это наоборот: сначала найдите все узлы с данным атрибутом, затем выполните соответствующая обработка на них.

Вы можете найти все узлы с атрибутом «class» «foo», например:

xml \\ "_" filter { _.attribute("class") == Some(Text("foo")) }

РЕДАКТИРОВАТЬ: Вы используете это так:

val markup = <html>...etc
val filtered = markup \\ "_" filter { _.attribute("class") == Some(Text("foo")) }
filtered map processNode

Если вы хотите вернуть некоторое значение из обработки, вам нужно сделать это по-другому, но ваш вопрос неясен в этом отношении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...