Scala XML Building:将子节点添加到现有节点
我有一个XML节点,我希望随着时间的推移添加子节点:
val root: Node = <model></model> 但我看不到像addChild()这样的方法,因为我想写下以下内容: def addToModel() = { root.addChild(<subsection>content</subsection>) } 因此,在单个调用此方法之后,根xml将是: <model><subsection>content</subsection></model> 我能看到的唯一可以附加节点的类是NodeBuffer.我错过了一些基本的东西吗? 解决方法
从这开始吧:
def addChild(n: Node,newChild: Node) = n match { case Elem(prefix,label,attribs,scope,child @ _*) => Elem(prefix,child ++ newChild : _*) case _ => error("Can only add children to elements!") } 这个方法在这里工作是因为child是Seq [Node],而newChild是一个Node,它扩展了NodeSeq,它扩展了Seq [Node]. 现在,这不会改变任何东西,因为Scala中的XML是不可变的.它将生成一个具有所需更改的新节点.唯一的成本是创建一个新的Elem对象,以及创建一个新的孩子Seq.子节点本身不会被复制,只是被引用,这不会导致问题,因为它们是不可变的. 但是,如果要将子节点添加到XML层次结构中的节点,则事情会变得复杂.一种方法是使用拉链,如this blog中所述. 但是,您可以使用scala.xml.transform,其规则将更改特定节点以添加新子节点.首先,编写一个新的变压器类: class AddChildrenTo(label: String,newChild: Node) extends RewriteRule { override def transform(n: Node) = n match { case n @ Elem(_,`label`,_,_*) => addChild(n,newChild) case other => other } } 然后,像这样使用它: val newXML = new RuleTransformer(new AddChildrenTo(parentName,newChild)).transform(oldXML).head 在Scala 2.7上,首先替换head. Scala 2.7上的示例: scala> val oldXML = <root><parent/></root> oldXML: scala.xml.Elem = <root><parent></parent></root> scala> val parentName = "parent" parentName: java.lang.String = parent scala> val newChild = <child/> newChild: scala.xml.Elem = <child></child> scala> val newXML = new RuleTransformer(new AddChildrenTo(parentName,newChild)).transform(oldXML).first newXML: scala.xml.Node = <root><parent><child></child></parent></root> 如果只是父元素不够,你可以使得获得正确元素变得更复杂.但是,如果您需要将子项添加到具有特定索引的公用名的父项,那么您可能需要采用拉链方式. 例如,如果您有< books>< book />< book />< / books>,并且您想要添加< author />到第二个,用规则变压器很难做到.你需要一个针对书籍的RewriteRule,然后它会得到它的孩子(它本应该被命名为孩子),在其中找到第n本书,将新孩子添加到其中,然后重构孩子并构建新节点.可行,但如果你必须做太多,拉链可能会更容易. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |