我目前正在使用Scala 3处理大的XML文件。我希望每个节点(XML元素)在没有读取所有属性和子节点时都能自动报告。我有一个解决方案,但感觉它不是很优雅,甚至可能有点滥用scala.util.Using
的原始用途。
object ReportingNode:
implicit val releasable: Releasable[ReportingNode] = node =>
node.assumeNoOtherAttributes()
node.assumeNoOtherChildren()
class ReportingNode(node: Node):
private val description = (node.label + " " + node \@ "OID").trim
private var accessedAttributes = Set[String]()
private var accessedChildren = Set[String]()
@targetName("attribute")
def \@(attributeName: String): String =
accessedAttributes += attributeName
node \@ attributeName
@targetName("children")
def \(childName: String): NodeSeq =
accessedChildren += childName
node \ childName
private def assumeNoOtherAttributes(): Unit =
for (attribute <- node.attributes)
if !accessedAttributes.contains(attribute.key) then
println(s"WARN $description has unexpected attribute ${attribute.key}")
private def assumeNoOtherChildren(): Unit =
for (child <- node.child)
if !(accessedChildren + "#PCDATA").contains(child.label) then
println(s"WARN $description has unexpected child ${child.label}")
类似<foo oid="42" name="bob"><bar...
的用法:
case class Foo(context: String, name: String, bars: Seq[Bar])
object Foo:
def apply(n: Node): Foo = Using.resource(ReportingNode(n))(node =>
val oid = node \@ "oid"
val name = node \@ "name"
val bars = (node \ "bar").map(Bar.apply)
Foo(oid, name, bars)
)
有没有办法把这样的事情做好?或者这已经是它得到的最好的了?
一些背景:你可能会问为什么我首先要把节点转换成一个自定义的结构。好吧,这里我简化了一点。XML是相当复杂的(CDISC ODM加上扩展),我的代码是解析对定义的引用,等等。
1条答案
按热度按时间ovfsdjhp1#
好吧,至少现在用法看起来干净了:
我通过将
Using
的内容移动到ReportingNode
对象中的apply
def来实现这一点:类别保持不变。