복붙노트

[SCALA] 스칼라 - XML에 중첩 된 요소를 수정

SCALA

스칼라 - XML에 중첩 된 요소를 수정

나는 스칼라을 배우고, 나는 일부 XML에서 중첩 된 노드를 업데이트 할 찾고 있어요. 나는 뭔가 작업을 가지고 있지만 가장 우아한 방법이 있는지 궁금 해요.

좀 XML을 가지고 :

val InputXml : Node =
<root>
    <subnode>
        <version>1</version>
    </subnode>
    <contents>
        <version>1</version>
    </contents>
</root>

그리고 난 버전 하위 노드에서 노드가 아니라 내용의 하나를 업데이트하고 싶습니다.

여기 내 기능은 다음과 같습니다

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

   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. ==============================

    1.나는 원래 논리가 좋은 생각합니다. 이것은 (? 내가 말을 감히된다)보다 스칼라 틱 맛을 가진 동일한 코드입니다 :

    나는 원래 논리가 좋은 생각합니다. 이것은 (? 내가 말을 감히된다)보다 스칼라 틱 맛을 가진 동일한 코드입니다 :

    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
       }
     }
    

    그것은 (:) 실제로 동일) 더 컴팩트 보인다

    당신이 원한다면, 당신은 너무 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
           }
    

    어떻게 생각해?

  2. ==============================

    2.이 모든 시간은 아무도 실제로 가장 적절한 답을주지 않았다! 지금은 그것을 배운 것을,하지만 여기에 나의 새로운 걸릴입니다 :

    이 모든 시간은 아무도 실제로 가장 적절한 답을주지 않았다! 지금은 그것을 배운 것을,하지만 여기에 나의 새로운 걸릴입니다 :

    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의 추상이다. 그것은 모두 변환이라는 두 가지 방법을 정의합니다. 그 중 하나는 단일 노드, 노드의 다른 시퀀스를합니다. 그것은 우리가 직접 인스턴스화 할 수 없습니다, 추상 클래스입니다. transformmethods이 경우 재정의 하나에, 정의를 추가함으로써, 우리는 그것의 익명의 하위 클래스를 만들 수 있습니다. 그것은 많은 작업을 수행 할 수 있지만 각 RewriteRule의 요구는 단일 작업 자체를 우려.

    다음에, 클래스 RuleTransformer 파라미터로 RewriteRule의 가변 개수 걸린다. 이 방법은 노드 소요 변환 및 각과를 인스턴스화하는 데 사용되는 모든 RewriteRule의를 적용하여, 노드의 순서를 반환합니다.

    두 클래스는 하나 개의 필요가 더 높은 수준에서 자신을 염려하지있는 몇 가지 방법을 정의 BasicTransformer에서 파생. 그것은 RuleTransformer와 RewriteRule의 모두가 그와 관련된 문법 설탕을 사용할 수 있도록 메서드 호출은,하지만, 변환을 적용합니다. 예에서, 전자는 않고, 나중에하지 않습니다.

    첫 번째 상위 레벨 노드에 필터를 적용하고, 두 번째 필터를 통과 무엇에 변경 사항을 적용 할 때 여기에서 우리는, RuleTransformer의 두 가지 수준을 사용합니다.

    추출기 Elem 모델은 그래서 같은 공간이나 속성 여부가 있는지 세부 자신 우려 할 필요가 없다는 것을 사용한다. 아니 요소 버전의 내용이 완전히 삭제하고 필요한 경우 그것은, 너무 대해 일치 할 수 있습니다 (2)로 대체된다.

    _ 추출기의 마지막 매개 변수가 _ * 있음도 참고하지. 즉, 이러한 요소들은 여러 아이를 가질 수 있습니다. 당신이 *를 잊어 버린 경우, 경기는 실패 할 수 있습니다. 어떤 공백이 없다면 예에서, 경기는 실패하지 않을 것입니다. 공백은 텍스트 요소로 변환되기 때문에, 하위 노드에서 하나의 공백이 실패하는 경기를 구분합니다.

    이 코드는 제시 한 다른 제안보다 큰,하지만 다른 사람보다 XML의 구조 훨씬 적은 지식을 가지고있는 장점이있다. 얼마나 많은 수준에 상관없이 - - 하위 노드라는 요소에 상관없이 네임 스페이스, 속성 등은 다음과 같습니다 버전이라는 모든 요소를 ​​변경

    당신이 할 수있는 많은 변형이있는 경우 또한 ... 음, 재귀 패턴 매칭 빠르게 탄력성이된다. RewriteRule의 및 RuleTransformer를 사용하면 효과적으로 스칼라 코드 파일을 XSLT 대체 할 수 있습니다.

  3. ==============================

    3.당신은 리프트의 CSS 선택기 변환 및 쓰기를 사용할 수 있습니다 :

    당신은 리프트의 CSS 선택기 변환 및 쓰기를 사용할 수 있습니다 :

    "subnode" #> ("version *" #> 2)
    

    http://stable.simply.liftweb.net/#sec:CSS-Selector-Transforms 참조

  4. ==============================

    4.나는 이래 배운 내가 다른 답변에서 우수한 솔루션으로 간주 할 것을 제시 하였다. 나는 내가 하위 노드 제한에 대한 계정에 실패했다 눈치 나는 또한이 일을 해결했습니다.

    나는 이래 배운 내가 다른 답변에서 우수한 솔루션으로 간주 할 것을 제시 하였다. 나는 내가 하위 노드 제한에 대한 계정에 실패했다 눈치 나는 또한이 일을 해결했습니다.

    질문 주셔서 감사합니다! XML을 처리 할 때 난 그냥 멋진 물건을 배웠다. 여기에 당신이 원하는 것입니다 :

    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)
    }
    

    이제 설명. 처음이자 마지막의 경우 문은 명백해야한다. 마지막 하나의 요소가 아니다는 XML의 그 부분을 잡기 위해 존재한다. 또는, 즉, 텍스트입니다. 첫 번째 문에 참고하지만, 플래그에 대한 테스트 버전이 변경되거나되지 않을 수 있는지 여부를 나타냅니다.

    두 번째와 세 번째의 경우 문은 객체 Elem 모델에 대해 패턴 매처를 사용합니다. 이 모든 구성 요소 부분으로 요소를 중단합니다. 마지막 매개 변수, "아이들은 @ _ *"아무것도의 목록에 아이를 일치합니다. 또는보다 구체적으로는, 서열 [노드]. 그렇다면 우리는 추출 된 부품, 소자를 재구성하지만 순환 공정 하 updateNodes에 서열 [노드]를 통과한다. 우리는 요소의 하위 노드에 일치하는 경우, 우리는 버전의 변화를 가능하게 true로 플래그 mayChange을 변경합니다.

    마지막 줄에서, 우리는 node.theSeq 서열을 생성하기 위해 사용 [노드] 노드 및 (0)에서 서열의 첫 번째 요소를 얻을 [노드] 결과로 반환. updateNodes이 (위해 ... 수율지도로 번역) 본질적으로지도 기능을하기 때문에, 우리는 결과가 하나 개의 요소 만이 알고 있습니다. 우리는 하위 노드 요소는 조상하지 않는 한 버전이 변경되지 않음을 보장하기 위해 거짓 깃발을 전달합니다.

    그 일을 약간 다른 방법은 더 강력하지만 좀 더 자세한하고, 모호한 것이있다 :

    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)
    }
    

    이 버전은 당신이 어떤 "버전"태그, 무엇이든 그것의 접두사, attribs 및 범위를 변경할 수 있습니다.

  5. ==============================

    5.저울 XML은 "대신에"편집 도구를 제공합니다. 물론 그 모든 불변 그러나 여기 스케일의 솔루션입니다 :

    저울 XML은 "대신에"편집 도구를 제공합니다. 물론 그 모든 불변 그러나 여기 스케일의 솔루션입니다 :

    val subnodes = top(xml).\*("subnode"l).\*("version"l)
    val folded = foldPositions( subnodes )( p => 
      Replace( p.tree ~> "2"))
    

    구문처럼의 XPath는 저울의 서명 기능, 그것은 네임 스페이스 (로컬 이름 만)이 없어야 문자열 지정 후 리터입니다.

    다시 함께 결합 결과 얻어진 소자 및 그 변형을 통해 foldPositions 반복.

  6. ==============================

    6.한 가지 방법은 렌즈 것 (예를 들어 scalaz의). 아주 명확 프레젠테이션 http://arosien.github.io/scalaz-base-talk-201208/#slide35를 참조하십시오.

    한 가지 방법은 렌즈 것 (예를 들어 scalaz의). 아주 명확 프레젠테이션 http://arosien.github.io/scalaz-base-talk-201208/#slide35를 참조하십시오.

  7. ==============================

    7.https://github.com/geirolz/advxml :이 프로젝트를 확인

    https://github.com/geirolz/advxml :이 프로젝트를 확인

    그것은 XML 변환 및 직렬화를 단순화하기위한 목적으로 RuleTransformer (표준 스칼라 XML 라이브러리)와 고양이를 기반으로 간단한 라이브러리이다.

  8. ==============================

    8.난 정말이가 우아하게 할 수있는 방법을 모르겠어요. FWIW, 나는 다른 접근을 위해 갈 것이다 : [정보] 당신이있는 거 처리를위한 사용자 정의 모델 클래스를 사용과 그것을위한 XML에서 변환을해야합니다. 당신은 아마이 데이터를 처리하는 더 좋은 방법입니다 찾을거야, 그것은 훨씬 더 간결합니다.

    난 정말이가 우아하게 할 수있는 방법을 모르겠어요. FWIW, 나는 다른 접근을 위해 갈 것이다 : [정보] 당신이있는 거 처리를위한 사용자 정의 모델 클래스를 사용과 그것을위한 XML에서 변환을해야합니다. 당신은 아마이 데이터를 처리하는 더 좋은 방법입니다 찾을거야, 그것은 훨씬 더 간결합니다.

    그러나 직접 XML을 함께 할 수있는 좋은 방법이있다, 나는 그것을보고 싶어요.

  9. from https://stackoverflow.com/questions/970675/scala-modifying-nested-elements-in-xml by cc-by-sa and MIT license