28장 working with xml - codeport/scala GitHub Wiki

##28.1 Semi-structured data

  • 스칼라는 XML처리를 지원한다.

##28.2 XML overview

  • 그냥 XML 설명임

##28.3 XML literals

  • XML을 리터럴로 사용할 수 있다.
scala> <a>
        This is some XML.
        Here is a tag: <atag/>
       </a>
res0: scala.xml.Elem = ...
  • XML 표현식은 Elem타입이 된다.

    • Node클래스는 모든 XML 노드 클래스의 추상 수퍼클래스다
    • Text클래스는 텍스트를 담고 있는 노드다.
    • NodeSeq클래스는 로드의 시퀀스를 담고 있다. 각 노드를 처리할 많은 메서드는 NodeSeq를 처리하지만 NodeNodeSeq를 상속받으므로 각 노드에서 메서드를 사용할 수 있다.
  • 이스케이프로 {}를 사용해서 XML 리터럴 가운데 스칼라코드를 작성할 수 있다.

scala> <a> {"hello"+", world"} </a>
  • {}는 스칼라코드를 포함해서 XML 리터럴도 포함할 수 있으므로 스칼라코드와 XML 리터럴 사이를 오갈 수 있다.
scala> val yearMade = 1955
scala> <a>{ if (yearMade < 2000) <old>{yearMade}</old>
            else xml.NodeSeq.Empty }
       </a>
  • 빈 노드는 xml.NodeSeq.Empty로 나타낸다.
  • <, >, &는 이스케이프되서 출력된다.
scala> <a> {"<a>potential security hole<a>"} </a>
res0: scala.xml.Elem = <a> &lt;/a&gt;potential security hole&lt;a&gt; </a>

##28.4 Serialization

  • 데이터 구조를 XML로 변환하려면 다음과 같은 toXML메서드를 정의한다.
abstract class Person {
  val name: String
  val age: Int

  def toXML = 
    <person>
      <name>{name}</name>
      <age>{age}</age>
    </person>
}

val p = new Person {
  val name = "outsider"
  val age = 25
}

p.toXML
  • XML 텍스트에 중괄호를 쓰려면 2번 써준다.
scala> <a>{{{{brace yourself!}}}} </a>
res0: scala.xml.Elem = <a> {{brace yourself!}} </a>

##28.5 Taking XML apart

  • XML에서 분리해내는 메서드들이 있고 이 메서드들은 XPath 언어에 기반한다.

  • 텍스트 추출 : 노드에서 text함수를 호출한다.

scala> <a>Sounds <tag/> good</a>.text
res0: String = Sounds good
  • 하위요소 추출 : 태그명으로 하위요소를 찾으려면 \ 태그명을 호출한다.
scala> <a><b><c>hello</c></b></a> \ "b"
res0: scala.xml.NodeSeq = <b><c>hello</c></b>
  • 하위의 하위요소를 찾으려면 \ 대신 \\를 사용한다.
scala> <a><b><c>hello</c></b></a> \ "c"
res0: scala.xml.NodeSeq = 
scala> <a><b><c>hello</c></b></a> \\ "c"
res1: scala.xml.NodeSeq = <c>hello</c>
  • 속성 추출 : 요소 추출과 똑같이 \, \\를 사용하지만 속성명앞에 @를 사용한다.
scala> val joe = <employee name="Joe" rank="code monkey"/>
scala> joe \ "@name"
res1: scala.xml.NodeSeq = Joe

##28.6 Deserialization

  • XML을 다시 데이터구조로 변환하려면 다음과 같은 fromXML 메서드를 정의한다.
def fromXML(node: scala.xml.Node): Person = 
  new Person {
    val name = (node \ "name").text
    val age = (node \ "age").text.toInt
  }

##28.7 Loading and saving

  • XML을 바이트의 파일로 변환하려면 XML.save를 사용한다.
scala.xml.XML.svve("filename.xml", node)
  • XML 파일을 로딩하려면 XML.loadFile을 사용한다.
val loadnode = xml.XML.loadFile("filename.xml")

##28.8 Pattern matching on XML

  • XML 패턴은 XML 리터럴처럼 보인다. 차이점은 {} 이스케이프를 사용했을 때 {}안의 코드는 표현식이 아니라 패턴이라는 점 뿐이다. {}내에서 스칼라 패턴언어를 모두 쓸 수 있다.
def proc(node: scala.xml.Node): String =
  node match {
    case <a>{contents}</a> => "It's an a: " + contents
    case <b>{contents}</b> => "It's an b: " + contents
    case _ => "It's something else."
  }
  • 위 코드는 중첩태그는 처리하지 못한다. XML 노드의 시퀀스에 대한 패턴은 _*로 작성한다.
def proc(node: scala.xml.Node): String =
  node match {
    case <a>{contents @ _*}</a> => "It's an a: " + contents
    case <b>{contents @ _*}</b> => "It's an b: " + contents
    case _ => "It's something else."
  }
  • XML 패턴은 for문에서도 잘 동작한다.
val catalog =
  <catalog>
    <cctherm>
      <description>hot dog #5</description>
      <yearMade>1952</yearMade>
    </cctherm>
    <cctherm>
      <description>Sprite Boy</description>
      <yearMade>1964</yearMade>
    </cctherm>

catalog match {
  case <catalog>{therms @ _*}</catalog> =>
    for (therm <- therms)
      println("processing: " + (therm \ "description").text)
}
processing:
processing: hot dog #5
processing:
processing: Sprite Boy
processing:
  • <cctherm>요소 앞뒤로 공백이 있어서 위처럼 출력된다. 공백을 무시하려면 다음과 같이 작성한다.
catalog match {
  case <catalog>{therms @ _*}</catalog> =>
    for (therm @ <cctherm>{_*}</cctherm> <- therms)
      println("processing: " + (therm \ "description").text)
}
⚠️ **GitHub.com Fallback** ⚠️