Scala - изменение вложенных элементов в xml

Просто другое решение: Я пытался получить тот же формат (ГГГГ-ММ-ДД ЧЧ: ММ: СС) , но date.getMonth () был найден неточным. Поэтому я решил получить формат самостоятельно.

Этот код был развернут в начале 2015 года, , и он прекрасно работает до настоящего времени.

var m_names =["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

var d = new Date();
var spl = d.toString().split(' ');
var mnth = parseInt(m_names.indexOf(spl[1])+1).toString();
mnth = (mnth.length == 1) ? '0'+mnth : mnth
        //  yyyy   -   mm   -   dd       hh:mm:ss 
var data = spl[3]+'-'+mnth+'-'+spl[2]+' '+spl[4]
alert(data)

Проверьте код в JSFIDDLE

37
задан Emil H 9 June 2009 в 15:19
поделиться

4 ответа

Я думаю, что исходная логика хороша. Это тот же самый код (осмелюсь ли сказать?), Более похожий на Scala:

def updateVersion( node : Node ) : Node = {
   def updateElements( seq : Seq[Node]) : Seq[Node] = 
     for( subNode <- seq ) yield updateVersion( subNode )  

   node match {
     case <root>{ ch @ _* }</root> => <root>{ updateElements( ch ) }</root>
     case <subnode>{ ch @ _* }</subnode> => <subnode>{ updateElements( ch ) }</subnode>
     case <version>{ contents }</version> => <version>2</version>
     case other @ _ => other
   }
 }

Он выглядит более компактным (но на самом деле тот же самый :))

  1. Я избавился от всего ненужного скобки
  2. Если скобка необходима, она начинается с та же строка
  3. updateElements просто определяет переменную и возвращает его, поэтому я избавился от этого и вернул результат напрямую

, если хотите, вы также можете избавиться от updateElements. Вы хотите применить updateVersion ко всем элементам последовательности. Это метод карты . При этом вы можете переписать строку

case <subnode>{ ch @ _* }</subnode> => <subnode>{ updateElements( ch ) }</subnode>

на

case <subnode>{ ch @ _* }</subnode> => <subnode>{ ch.map(updateVersion (_)) }</subnode>

Поскольку версия обновления принимает только 1 параметр, я на 99% уверен, что вы можете пропустить его и написать:

case <subnode>{ ch @ _* }</subnode> => <subnode>{ ch.map(updateVersion) }</subnode>

И закончить:

def updateVersion( node : Node ) : Node = node match {
         case <root>{ ch @ _* }</root> => <root>{ ch.map(updateVersion )}</root>
         case <subnode>{ ch @ _* }</subnode> => <subnode>{ ch.map(updateVersion ) }</subnode>
         case <version>{ contents }</version> => <version>2</version>
         case other @ _ => other
       }

Как вы думаете?

12
ответ дан 27 November 2019 в 04:23
поделиться

Я действительно не знаю, как это можно сделать изящно. FWIW, я бы выбрал другой подход: использовать собственный класс модели для информации, которую вы обрабатываете, и преобразовывать ее в Xml и обратно. Вы, вероятно, обнаружите, что это лучший способ обработки данных, и он даже более лаконичный.

Однако есть хороший способ сделать это напрямую с помощью Xml, я бы хотел его увидеть.

-2
ответ дан 27 November 2019 в 04:23
поделиться

I have since learned more and presented what I deem to be a superior solution in another answer. I have also fixed this one, as I noticed I was failing to account for the subnode restriction.

Thanks for the question! I just learned some cool stuff when dealing with XML. Here is what you want:

def updateVersion(node: Node): Node = {
  def updateNodes(ns: Seq[Node], mayChange: Boolean): Seq[Node] =
    for(subnode <- ns) yield subnode match {
      case <version>{ _ }</version> if mayChange => <version>2</version>
      case Elem(prefix, "subnode", attribs, scope, children @ _*) =>
        Elem(prefix, "subnode", attribs, scope, updateNodes(children, true) : _*)
      case Elem(prefix, label, attribs, scope, children @ _*) =>
        Elem(prefix, label, attribs, scope, updateNodes(children, mayChange) : _*)
      case other => other  // preserve text
    }

  updateNodes(node.theSeq, false)(0)
}

Now, explanation. First and last case statements should be obvious. The last one exists to catch those parts of an XML which are not elements. Or, in other words, text. Note in the first statement, though, the test against the flag to indicate whether version may be changed or not.

The second and third case statements will use a pattern matcher against the object Elem. This will break an element into all its component parts. The last parameter, "children @ _*", will match children to a list of anything. Or, more specifically, a Seq[Node]. Then we reconstruct the element, with the parts we extracted, but pass the Seq[Node] to updateNodes, doing the recursion step. If we are matching against the element subnode, then we change the flag mayChange to true, enabling the change of the version.

In the last line, we use node.theSeq to generate a Seq[Node] from Node, and (0) to get the first element of the Seq[Node] returned as result. Since updateNodes is essentially a map function (for ... yield is translated into map), we know the result will only have one element. We pass a false flag to ensure that no version will be changed unless a subnode element is an ancestor.

There is a slightly different way of doing it, that's more powerful but a bit more verbose and obscure:

def updateVersion(node: Node): Node = {
  def updateNodes(ns: Seq[Node], mayChange: Boolean): Seq[Node] =
    for(subnode <- ns) yield subnode match {
      case Elem(prefix, "version", attribs, scope, Text(_)) if mayChange => 
        Elem(prefix, "version", attribs, scope, Text("2"))
      case Elem(prefix, "subnode", attribs, scope, children @ _*) =>
        Elem(prefix, "subnode", attribs, scope, updateNodes(children, true) : _*)
      case Elem(prefix, label, attribs, scope, children @ _*) =>
        Elem(prefix, label, attribs, scope, updateNodes(children, mayChange) : _*)
      case other => other  // preserve text
    }

  updateNodes(node.theSeq, false)(0)
}

This version allows you to change any "version" tag, whatever it's prefix, attribs and scope.

6
ответ дан 27 November 2019 в 04:23
поделиться

Все на этот раз, и на самом деле никто не дал наиболее подходящего ответа! Теперь, когда я узнал об этом, вот мой новый взгляд на это:

import scala.xml._
import scala.xml.transform._

object t1 extends RewriteRule {
  override def transform(n: Node): Seq[Node] = n match {
    case Elem(prefix, "version", attribs, scope, _*)  =>
      Elem(prefix, "version", attribs, scope, Text("2"))
    case other => other
  }
}

object rt1 extends RuleTransformer(t1)

object t2 extends RewriteRule {
  override def transform(n: Node): Seq[Node] = n match {
    case sn @ Elem(_, "subnode", _, _, _*) => rt1(sn)
    case other => other
  }
}

object rt2 extends RuleTransformer(t2)

rt2(InputXml)

Теперь несколько объяснений. Класс RewriteRule является абстрактным. Он определяет два метода, оба называются преобразованием . Один из них занимает единственный Узел , другой - Последовательность из Узла . Это абстрактный класс, поэтому мы не можем создать его экземпляр напрямую. Добавляя определение, в данном случае переопределив один из методов transform , мы создаем его анонимный подкласс. Каждое RewriteRule должно заниматься одной задачей, хотя он может делать многие.

Затем класс RuleTransformer принимает в качестве параметров переменное число RewriteRule . Этот метод преобразования принимает Узел и возвращает Последовательность из Узла , применяя каждое RewriteRule , используемое для его создания.

] Оба класса являются производными от BasicTransformer , который определяет несколько методов, которыми не нужно заниматься на более высоком уровне. Это метод apply , вызовы , преобразование , поэтому оба RuleTransformer и RewriteRule могут использовать связанный с ним синтаксический сахар. В этом примере первое делает, а второе - нет.

Здесь мы используем два уровня RuleTransformer , поскольку первый применяет фильтр к узлам более высокого уровня, а второй применяет изменения ко всему, что проходит фильтр.

Также используется экстрактор Elem , так что нет необходимости беспокоиться о деталях например, пространство имен или наличие атрибутов. Это не значит, что содержимое элемента версии полностью отбрасывается и заменяется на 2 . При необходимости его также можно сопоставить.

Обратите внимание, что последний параметр экстрактора - _ * , а не _ . Это означает, что у этих элементов может быть несколько дочерних элементов. Если вы забудете * , сопоставление может не пройти. В этом примере совпадение не завершилось бы ошибкой, если бы не было пробелов. Поскольку пробелы переводятся в элементы Text , одиночный пробел в подузле приведет к сбою сопоставления.

Этот код больше, чем другие представленные предложения, но он имеет то преимущество, что он гораздо меньше знает структуру XML, чем другие . Он изменяет любой элемент, называемый версией , который находится ниже - независимо от того, сколько уровней - элемент, называемый подузлом , независимо от пространства имен, атрибутов и т. Д.

Кроме того ... Что ж, если вам нужно сделать много преобразований, рекурсивное сопоставление с образцом быстро становится непреодолимым. Используя RewriteRule и RuleTransformer , вы можете эффективно заменить файлы xslt кодом Scala.

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

Кроме того ... Что ж, если вам нужно сделать много преобразований, рекурсивное сопоставление с образцом быстро становится непреодолимым. Используя RewriteRule и RuleTransformer , вы можете эффективно заменить файлы xslt кодом Scala.

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

Кроме того ... Что ж, если вам нужно сделать много преобразований, рекурсивное сопоставление с образцом быстро становится непреодолимым. Используя RewriteRule и RuleTransformer , вы можете эффективно заменить файлы xslt кодом Scala.

если вам нужно сделать много преобразований, рекурсивное сопоставление с образцом быстро становится неудобным. Используя RewriteRule и RuleTransformer , вы можете эффективно заменить файлы xslt кодом Scala.

если вам нужно сделать много преобразований, рекурсивное сопоставление с образцом быстро становится неудобным. Используя RewriteRule и RuleTransformer , вы можете эффективно заменить файлы xslt кодом Scala.

56
ответ дан 27 November 2019 в 04:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: