Scala:合并数据的 xml 树?

发布于 2024-12-10 18:23:33 字数 468 浏览 0 评论 0原文

我很好奇组合一组包含类似内容的 xml 树的最佳方法 数据到单个集合(“联合”样式)。

我确实实现了一个可行的解决方案,但代码看起来很糟糕,我有 强烈的直觉,一定有一种更好、更紧凑的方式 实施这一点。

我想做的是在最简单的情况下结合以下内容:

<fruit> <apple /> <orange /> </fruit>

和:

<fruit> <banana /> </fruit>

To:

<fruit> <apple/> <orange/> <banana/> </fruit>

有什么好主意如何在 scala 中干净地实现这个功能吗?

I'm curious for the best way to combine a set of xml trees containing similar
data to a single set ('union' style).

I did implement a working solution but the code looks bad and I have
a strong gut feeling that there must be a much nicer and compact way of
implementing this.

What I'm trying to do is in the simplest case combining something like:

<fruit> <apple /> <orange /> </fruit>

and:

<fruit> <banana /> </fruit>

To:

<fruit> <apple/> <orange/> <banana/> </fruit>

Any good ideas how to make a clean implementation of this in scala?

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

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

发布评论

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

评论(2

冰火雁神 2024-12-17 18:23:33

但是

val appleAndOrange : Elem = <fruit> <apple/> <orange/> </fruit>

这只是

val banana : Elem = <fruit> <banana> </fruit>

val all = appleAndOrange.copy(child = appleAndOrange.child ++ banana.child)

appleAndOrange 中获取标签 ,并忽略 banana 中的标签,这里是恰好是一样的。同样,如果它们不相同,您必须决定需要什么检查以及什么行为。前缀、属性和范围也是如此。

with

val appleAndOrange : Elem = <fruit> <apple/> <orange/> </fruit>

and

val banana : Elem = <fruit> <banana> </fruit>

you can do

val all = appleAndOrange.copy(child = appleAndOrange.child ++ banana.child)

However, this simply takes the the label <fruit> from appleAndOrange, and ignore the one from banana, which here happens to be the same. Same for You have to decide what checks you want and what behavior, if they are not the same. Same for prefixes, attributes, and scopes.

じее 2024-12-17 18:23:33

这是另一种值得考虑的方法。我们本质上是从字符串构建 scala.xml.Elem 并使用一些 XPath 样式查询。

import scala.xml._
def childUnion(parent: String, a: Elem, b: Elem): Elem = {
    val open:String = "<" + parent + ">"
    val close:String = "</" + parent + ">"
    val children = a \\ parent \ "_" ++ b \\ parent \ "_"
    return XML.loadString(open + children + close)
}

首先,我们创建了 openclose 标记,它们只是字符串。然后我们使用一些 XPath 样式查询构造 children

\\ 是 Elem 上的一个运算符,它返回 Elem 的元素和所有子序列。

\ 类似,但它返回 Elem 的元素。

“_” 是通配符。

为什么不只是\?我自己根据文档很难弄清楚这一点,但是查看 XPath for Java 让我相信 \\ 包含整个 Elem 本身和子元素,而 \ 仅包含孩子,所以如果我们有 \ "parent" 我们什么也找不到,因为只传递了

现在这个方法并不牛逼。我们能做些什么来让它变得更棒呢?我们最好利用 Scala 精彩的 Option 类和 foldLeft 方法。

def childUnion(parent: String, a: Elem, b: Elem*): Option[Elem] = {
    val parentElem = a \\ parent

    parentElem.size match {
        case 0 => None // no parent present
        case _ => 
            val children = b.foldLeft(parentElem \ "_")((d,c) => (d ++ (c \\ parent \ "_")))
            val open:String = "<" + parent + ">"
            val close:String = "</" + parent + ">"
            Some(XML.loadString(open + children + close))
    }
}

当然,这还有一个额外的好处,即仅处理一个 Elem(父级不存在的情况)以及作为参数提供的可变数量的 Elem。这是我在提出这个最终方法时运行的一长串示例,

scala> a
res85: scala.xml.Elem = <fruit> <apple></apple> <orange></orange> </fruit>

scala> b
res86: scala.xml.Elem = <fruit> <banana></banana> </fruit>

scala> c
res87: scala.xml.Elem = <box><fruit><apple></apple></fruit></box>

scala> d
res88: scala.xml.Elem = <box><nofruit></nofruit></box>

scala> e
res89: scala.xml.Elem = <fruit></fruit>

scala> val f = <fruit />
f: scala.xml.Elem = <fruit></fruit>

scala> childUnion("fruit", a)
res91: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)

scala> childUnion("fruit", b)
res92: Option[scala.xml.Elem] = Some(<fruit><banana></banana></fruit>)

scala> childUnion("fruit", c)
res93: Option[scala.xml.Elem] = Some(<fruit><apple></apple></fruit>)

scala> childUnion("fruit", d)
res94: Option[scala.xml.Elem] = None

scala> childUnion("fruit", e)
res95: Option[scala.xml.Elem] = Some(<fruit></fruit>)

scala> childUnion("fruit", a, b)
res96: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><banana></banana></fruit>)

scala> childUnion("fruit", a, e)
res97: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)

scala> childUnion("fruit", a, c)
res98: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><apple></apple></fruit>)

scala> childUnion("fruit", a, d)
res99: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)

scala> childUnion("fruit", e, d)
res100: Option[scala.xml.Elem] = Some(<fruit></fruit>)

scala> childUnion("fruit", d, d)
res101: Option[scala.xml.Elem] = None

scala> childUnion("fruit", f)
res102: Option[scala.xml.Elem] = Some(<fruit></fruit>)

Here is another approach that is worth considering. We're essentially going to be building the scala.xml.Elem from a string and making use of some XPath style querying.

import scala.xml._
def childUnion(parent: String, a: Elem, b: Elem): Elem = {
    val open:String = "<" + parent + ">"
    val close:String = "</" + parent + ">"
    val children = a \\ parent \ "_" ++ b \\ parent \ "_"
    return XML.loadString(open + children + close)
}

First we created the open and close tags, which are just strings. Then we construct children by using some XPath style query.

\\ is an operator on Elem which returns elements and all subsequences of the Elem.

\ is similar but it returns the elements of the Elem.

"_" is the wildcard.

Why not just \? I had trouble figuring this out myself based on the documentation but looking at XPath for Java leads me to believe that \\ includes the entire Elem itself and children while \ only includes the children, so if we had <parent><x/></parent> \ "parent" we would find nothing since only <x/> is passed.

Now this method is not awesome. What can we do to make it a bit more awesome? We'd better make use of Scala's wonderful Option class and the foldLeft method.

def childUnion(parent: String, a: Elem, b: Elem*): Option[Elem] = {
    val parentElem = a \\ parent

    parentElem.size match {
        case 0 => None // no parent present
        case _ => 
            val children = b.foldLeft(parentElem \ "_")((d,c) => (d ++ (c \\ parent \ "_")))
            val open:String = "<" + parent + ">"
            val close:String = "</" + parent + ">"
            Some(XML.loadString(open + children + close))
    }
}

This of course has the sweetly added benefit of working on just one Elem, cases where the parent is not present, and a variable number of Elem provided as arguments. Here is a long list of examples I ran while coming up with this final method,

scala> a
res85: scala.xml.Elem = <fruit> <apple></apple> <orange></orange> </fruit>

scala> b
res86: scala.xml.Elem = <fruit> <banana></banana> </fruit>

scala> c
res87: scala.xml.Elem = <box><fruit><apple></apple></fruit></box>

scala> d
res88: scala.xml.Elem = <box><nofruit></nofruit></box>

scala> e
res89: scala.xml.Elem = <fruit></fruit>

scala> val f = <fruit />
f: scala.xml.Elem = <fruit></fruit>

scala> childUnion("fruit", a)
res91: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)

scala> childUnion("fruit", b)
res92: Option[scala.xml.Elem] = Some(<fruit><banana></banana></fruit>)

scala> childUnion("fruit", c)
res93: Option[scala.xml.Elem] = Some(<fruit><apple></apple></fruit>)

scala> childUnion("fruit", d)
res94: Option[scala.xml.Elem] = None

scala> childUnion("fruit", e)
res95: Option[scala.xml.Elem] = Some(<fruit></fruit>)

scala> childUnion("fruit", a, b)
res96: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><banana></banana></fruit>)

scala> childUnion("fruit", a, e)
res97: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)

scala> childUnion("fruit", a, c)
res98: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><apple></apple></fruit>)

scala> childUnion("fruit", a, d)
res99: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)

scala> childUnion("fruit", e, d)
res100: Option[scala.xml.Elem] = Some(<fruit></fruit>)

scala> childUnion("fruit", d, d)
res101: Option[scala.xml.Elem] = None

scala> childUnion("fruit", f)
res102: Option[scala.xml.Elem] = Some(<fruit></fruit>)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文