我刚刚开始使用Scala进行编码,我在使用这个非常基本的XML结构时遇到了困难:
<Countries>
<Country>
<Name>Italy</Name>
<Continent>Europe</Continent>
</Country>
<Country>
<Name>Japan</Name>
<Continent>Asia</Continent>
</Country>
</Countries>
问题1:我想在文件中添加一个新节点(一个新的国家/地区)。我使用XML.loadFile成功加载了文件,但不知道如何添加新节点,然后保存文件。
问题2:我还想删除文件中的节点,但即使在这里,我也很难找到我想要的东西,特别是因为我想删除元素与用户输入的国家名称匹配的节点。
我使用了我在网上找到的一段代码:
val removeIt = new RewriteRule {
override def transform(n: Node): NodeSeq = n match {
case e: Elem if (e \ "Name").text == "Japan" => NodeSeq.Empty
case n => n
}
}
这样可行,但不幸的是它返回一个不被接受作为Xml.Save参数的NodeSeq,而且我也不知道如何传递一个String参数来确定要删除的节点。
答案 0 :(得分:3)
假设我将您的示例xml代码放在Country.xml中。
<Countries>
<Country>
<Name>Italy</Name>
<Continent>Europe</Continent>
</Country>
<Country>
<Name>Japan</Name>
<Continent>Asia</Continent>
</Country>
</Countries>
以下是我如何尝试完成它
object XMLLoader extends App {
def toBeAddedEntry(name: String, continent: String) =
<Country>
<Name>{ name }</Name>
<Continent>{ continent }</Continent>
</Country>
// For problem 1 How to add a new Node
def addNewEntry(originalXML: Elem, name: String, continent: String) = {
originalXML match {
case <Countries>{ innerProps @ _* }</Countries> => {
<Countries> {
innerProps ++ toBeAddedEntry(name, continent)
}</Countries>
}
case other => other
}
}
// For problem 2 How to delete node with element Name with certain value
def deleteEntry(originalXML: Elem, nameValue: String) = {
originalXML match {
/*
Considering you just start coding in Scala, the following explanation may help:
Here Elem is used as Extractor, actually the unapplySeq in Elem object is invoked
def unapplySeq(n: Node) = n match {
case _: SpecialNode | _: Group => None
case _ => Some((n.prefix, n.label, n.attributes, n.scope, n.child))
}
Then we use sequence pattern(match against a sequence without specifying how long it can be) to
extract child of originalXML and do the filtering job
*/
case e @ Elem(_, _, _, _, countries @ _*) => {
/*
original is kind of like
<Country>
<Name>Japan</Name>
<Continent>Asia</Continent>
</Country>
*/
val changedNodes = countries filter { country =>
(original \ "Name").exists(elem => elem.text != nameValue)
}
e.copy(child = changedNodes)
}
case _ => originalXML
}
}
// define your own way to load Country.xml
val originalXML = XML.load(getClass.getClassLoader.getResourceAsStream("Country.xml"))
val printer = new scala.xml.PrettyPrinter(80,5)
println(printer.format(addNewEntry(originalXML, "China", "Asia")))
println(printer.format(deleteEntry(originalXML, "Japan")))
}
结果如下:
<Countries>
<Country>
<Name>Italy</Name>
<Continent>Europe</Continent>
</Country>
<Country>
<Name>Japan</Name>
<Continent>Asia</Continent>
</Country>
<Country>
<Name>China</Name>
<Continent>Asia</Continent>
</Country>
</Countries>
<Countries>
<Country>
<Name>Italy</Name>
<Continent>Europe</Continent>
</Country>
</Countries>
剩下的部分是关于将Node写回Country.xml。无论如何,希望它有所帮助。