Добавить или добавить новый элемент в файл XML в Scala вместо его замены

Мой код scala в настоящее время заменяет весь раздел моего xml-файла новым тегом, который я добавляю. Я хочу, чтобы он добавлял тег только один раз в качестве дочернего элемента ClientConfig, но заменял собой все теги, присутствующие в этом разделе.

val data = XML.load(file)
val p = new XMLPrettyPrinter(2)
val tryingtoAdd = addNewEntry(data,host,env)
p.write(tryingtoAdd)(System.out)

где host=bob и env=flat определены ранее, а addNewEntry определяется следующим образом

 private def isCorrectLocation(parent: Elem, node: Elem, host: String): Boolean = {
    parent.label == "ClientConfig" && node.label == "host"
  }

  def addNewEntry(elem:Elem, host: String, env: String): Elem ={
    val toAdd = <host name={host} env={env} />
    def addNew(current: Elem): Elem = current.copy(
      child = current.child.map {
        case e: Elem if isCorrectLocation(current, e, host) ⇒ toAdd
        case e: Elem ⇒ addNew(e)
        case other ⇒ other
      }
    )
    addNew(elem)
  }

XML, который он создает,

<ClientConfig>
    <host name="bob" env="flat"/>
    <host name="bob" env="flat"/>
    <host name="bob" env="flat"/>
    <host name="bob" env="flat"/>
</ClientConfig>

где вместо этого я хочу, чтобы он просто добавлял его как один дочерний элемент ClientConfig, например, где последние три дочерних элемента уже присутствовали в файле

<ClientConfig>
    <host name="bob" env="flat"/>
    <host name="george" env="flat"/>
    <host name="alice" env="flat"/>
    <host name="bernice" env="flat"/>
</ClientConfig>

Что я делаю? Например, у python есть простой метод вставки


person Zee    schedule 31.07.2015    source источник


Ответы (2)


В вашем случае, когда совпадение с образцом переходит к

case e: Elem if isCorrectLocation(current, e, host) => toAdd

Метод toAdd будет использовать хост, env, который вы передаете в addNewEntry(data, host, env). боб для хозяина, квартира для окружающей среды. Итак, toAdd всегда будет возвращать <host name="bob" env="flat"/>.

Предположим, что у вас есть client.xml следующим образом:

   <Root>
     <ServerConfig>
       <host name="allen" env="flat"/>
     </ServerConfig>
     <ClientConfig>
       <host name="george" env="flat"/>
       <host name="alice" env="flat"/>
       <host name="bernice" env="flat"/>
    </ClientConfig>
   </Root>

Следующий код - это то, как я пытаюсь это сделать.

    def toBeAddedEntry(name: String, env: String) = <host name={ name } env={ env } />
    def addNewEntry(originalXML: Elem, name: String, env: String) = {
      originalXML match {
         case e @ Elem(_, _, _, _, configs @ _*) => {
            val changedNodes = configs.map {
                case <ClientConfig>{ innerConfigs @ _* }</ClientConfig> => {
                    <ClientConfig> { toBeAddedEntry(name, env) ++ innerConfigs }</ClientConfig>
                }
                case other => other
             }
            e.copy(child = changedNodes)
         }
         case _ => originalXML
     }
   }   

    val originalXML = XML.load("client.xml")
    val printer = new scala.xml.PrettyPrinter(80,5)
    println(printer.format(addNewEntry(originalXML, "bob", "flat")))


    // result
    <Root>
      <ServerConfig>
        <host env="flat" name="allen"/>
     </ServerConfig>
     <ClientConfig>
       <host name="bob" env="flat"/>
       <host env="flat" name="george"/>
       <host env="flat" name="alice"/>
       <host env="flat" name="bernice"/>
    </ClientConfig>
   </Root>

Кроме того, я замечаю одну вещь во время процесса. XML.load на самом деле меняет порядок атрибутов на противоположный, возможно, это не имеет отношения к решению вашей проблемы, но просто добавив его сюда, если вам это нужно.

person Allen Chou    schedule 01.08.2015
comment
Откуда взялся метод toBeAddedEntry? Кажется, выдает ошибку, когда я компилирую это - person Zee; 03.08.2015
comment
@Zee, извините, я виноват, только что добавил. - person Allen Chou; 03.08.2015
comment
Исправлена ​​последняя проблема! Еще вопрос, при чем здесь должны быть конфиги? - person Zee; 03.08.2015
comment
@Zee, если вы посмотрите на определение Elem, вы узнаете, что конфигурации с типом Seq[Node] на самом деле означают узел между ‹ClientConfig›‹/ClientConfig›, простой способ проверить это — распечатать его. - person Allen Chou; 03.08.2015
comment
кажется, что узел добавляется за пределы clientconfig. Когда я указываю место для добавления, например (originalXML\\ ClientConfig), это дает несоответствие типа. Как вы получаете его для добавления внутри тега ClientConfig - person Zee; 03.08.2015
comment
@Zee, эй, зачем ты делаешь этот originalXML\\ ClientConfig, я отредактировал свой ответ. Кажется, вы не совсем понимаете структуру originalXML. Я использую шаблон для извлечения Seq[Node] из ClientConfig, а затем вношу некоторые изменения. - person Allen Chou; 03.08.2015
comment
Проблема в том, что он, кажется, произвольно добавляет его выше и вне области ClientConfig файла xml. Вы просто используете весь файл в своем методе загрузки XML? - person Zee; 03.08.2015
comment
Давайте продолжим обсуждение в чате. - person Allen Chou; 03.08.2015
comment
Извините за это, да, я просто загружаю весь файл в формате XML. Итак, что я пропустил, пожалуйста, скажите мне. - person Allen Chou; 03.08.2015
comment
Перед тегом ClientConfig есть xml, и когда я использую ваш код, он добавляет его вне тега ClientConfig, поэтому, например, он добавляет его ‹xml› ‹host env=flat name=bob› ‹Client Config› ‹host env= flat name=george/› ‹host env=flat name=alice/› ‹host env=flat name=bernice/› ‹/ClientConfig› - person Zee; 03.08.2015
comment
Итак, вы имеете в виду, что в файле, который я собираюсь загрузить, структура на самом деле похожа на ‹ServerConfig›‹host name=george env=flat/›‹/ServerConfig› ‹ClientConfig›‹host name=george env=flat/›‹host name= alice env=flat/›‹host name=bernice env=flat/›‹/ClientConfig›, и вы хотите добавить ‹host name=bob env=flat/› в качестве первого потомка ‹ClientConfig›‹/ClientConfig›, не так ли? Правильно? - person Allen Chou; 03.08.2015
comment
@Zee, эй, проверь отредактированный ответ, надеюсь, на этот раз я правильно понял. - person Allen Chou; 03.08.2015
comment
@Zee, ха-ха, слава богу, я тоже немного устал. Эй, я случайно заметил, что вы задали несколько вопросов о Scala XML, поэтому я предлагаю вам внимательно прочитать главу «Работа с XML» в «Программировании на Scala», это может очень помочь. Кроме того, вам лучше предоставить более подробную информацию о вопросе, который вы собираетесь задать в следующий раз, чтобы помочь другим лучше понять ваши проблемы. В вашем случае структура файла xml. вы видите, что мы оба тратим много времени на прояснение реальной проблемы вопроса. Во всяком случае, сделать это. - person Allen Chou; 03.08.2015
comment
На самом деле я прочитал всю главу о Scala XML из книги Одерски, но я очень новичок в Scala, и примеры в книге были очень простыми по сравнению с этим. Не смотря ни на что, я продолжаю читать - person Zee; 03.08.2015
comment
По правде говоря, когда я был новичком, я начал читать эту книгу, тоже запутавшись. Да, вы должны продолжать. После решения ряда проблем Scala XML, держу пари, вы лучше поймете эту главу. Так вот, удачи!! - person Allen Chou; 03.08.2015

https://github.com/geirolz/advxml

это простая библиотека для упрощения преобразования XML

person David Geirola    schedule 03.08.2019