【问题标题】:Scala: How to append new node to an XML file and how to delete a node from an XML fileScala:如何将新节点附加到 XML 文件以及如何从 XML 文件中删除节点
【发布时间】:2015-08-20 23:36:05
【问题描述】:

我刚刚开始使用 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,而且我不知道如何传递一个字符串参数来确定要删除哪个节点。

【问题讨论】:

    标签: xml scala


    【解决方案1】:

    假设我将您的示例 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。无论如何,希望它有所帮助。

    【讨论】:

    • 完美,非常感谢 - 如果您想解释一些逻辑,例如这一行,我将不胜感激:Elem(_, _, _, _ etc
    猜你喜欢
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-19
    • 1970-01-01
    • 2011-12-19
    相关资源
    最近更新 更多