如何使用 scala.xml.Node 向上遍历单个子节点

发布于 2024-10-13 02:11:19 字数 991 浏览 1 评论 0原文

扩展我之前提出的关于如何迭代 scala.xml.Node 中的节点集合的问题,发现 这里

我想更进一步,询问如何在递归函数中查找前一个子节点一旦我遇到特定情况,就会得到一个值

例如(标记在这里)

<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 语句中添加什么来直接提取这个值吗?另外,如何从该 fx 返回字符串值?带有简单返回线的中断或?

Expanding on a question I asked earlier about how to iterate over a collection of nodes in scala.xml.Node found here

I wanted to take this 1 step further and ask how I could look up to a previous child inside a recursive function to get a value once I hit a specific situation

For example (the markup is here)

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

With my current implementation (thanks to @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
}

I want to add another conditional to get the text "foo" from inside the class section

Any idea what I could add inside this if statement to pull this value directly? Also how can I return the String value from this fx? a break w/ a simple return line or ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

终止放荡 2024-10-20 02:11:19

请注意,示例中 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)

为了方便起见,在默认没有父节点的情况下,创建一个隐式函数将节点转换为超级节点。

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))) }
}

Note that the parent of the Text node in your example is actually the <title> node.

Since Nodes don't have references to their parents, one way to access them is just to pass them with you when walking down the tree, like this:

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)

Of course, this becomes unwieldy when you want to climb back up the tree to an arbitrary level. One approach to this is to wrap your nodes in a SuperNode that has an optional parent reference.

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

For convenience, make an implicit function to convert nodes to SuperNodes in the default case of no parent.

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

Now you can navigate up the tree an arbitrary number of times, like this:

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))) }
}
又怨 2024-10-20 02:11:19

如果你继续朝这个方向前进,你应该使用 XML 拉链。我认为 Scalaz 有一个(它有一个,但我不确定您是否可以使用它与 XML)。

If you keep going in this direction, you should use an XML Zipper. I think Scalaz has one (it has one, but I'm not sure if you can use it with XML).

淡墨 2024-10-20 02:11:19

如果您想对值执行某些操作(如果该值位于具有特定属性的节点内),则可以反过来执行:首先查找具有给定属性的所有节点,然后执行相关操作对它们进行处理。

您可以找到具有“foo”的“class”属性的所有节点,如下所示:

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

编辑:您可以这样使用它:

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

如果您想从处理中返回一些值,您需要以不同的方式进行操作,但你的问题对此并不清楚。

If you want to do something with the value only if it is inside a node with a certain attribute, you can do it the other way around: first find all nodes with the given attribute, then do the relevant processing on them.

You can find all nodes with a "class" attribute of "foo" like this:

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

EDIT: You use it like this:

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

If you want to return some value from the processing you need to do it differently, but your question is not clear in regards to that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文