scala unmarshelling xml想要捕获cdata字段

时间:2016-02-16 17:59:44

标签: xml scala pattern-matching

我正在使用包含嵌入式xml文档的CDATA字段解析XML文档,并且我想要解组所有这些文档。遗憾的是,DOM的scala xml解析器正在检索<。![CDATA []]> cdata字段中的标记。我如何接受它?到目前为止,我的尝试是尝试按以下方式对元素进行模式匹配:

 node match {
    case Elem(_, _, _, _, Text(text)) => {
      if(text.startsWith("<") && text.endsWith(">")) map put(CDATA, fromXml(text))
      else                                           map put(TEXT, text)
    }
    case Elem(_, _, _, _, PCData(text)) => println(text) /* CDATA! */
    case _ => map ++= seqLoop(node \ "_") /* Not element must call children recursively */
  }

正如你所看到的那样,我试图用cdata对模式匹配元素,它完全落在Text上,我只能用那个丑陋的情况检测它。如果是这样的话。

任何帮助?

2 个答案:

答案 0 :(得分:2)

总而言之,做这件事并不是一个好主意。 <foo>&lt;bar/&gt;</foo><foo><![CDATA[<bar/>]]></foo>是等效的。这些只是逃避特殊字符的一些不同方法。您shouldn't depend在源上返回一个或另一个。

如果您可以控制架构,则应使用其他属性或元素来指定文本数据是XML格式。

也就是说,在解析XML字符串或文件时,似乎可以劫持scala XML库以生成CData部分的PCData元素:

import scala.xml.{TopScope, InputSource, SAXParser, Elem, PCData}
import scala.xml.parsing.FactoryAdapter
import scala.xml.factory.XMLLoader
import org.xml.sax.ext.{LexicalHandler, DefaultHandler2}

object XMLLoaderWithCData extends XMLLoader[Elem] {
  def lexicalHandler(adapter: FactoryAdapter): LexicalHandler = 
    new DefaultHandler2 {
      def captureCData(): Unit = {
        adapter.hStack push PCData(adapter.buffer.toString)
        adapter.buffer.clear()
      }

      override def startCDATA(): Unit = adapter.captureText()
      override def endCDATA(): Unit = captureCData()
    }

  override def loadXML(source: InputSource, parser: SAXParser): Elem = {
    val newAdapter = adapter

    val xmlReader = parser.getXMLReader
    xmlReader.setProperty(
      "http://xml.org/sax/properties/lexical-handler", 
      lexicalHandler(newAdapter))

    newAdapter.scopeStack push TopScope
    parser.parse(source, newAdapter)
    newAdapter.scopeStack.pop()

    newAdapter.rootElem.asInstanceOf[Elem]
  }
}

您可以将此XMLLoaderWithCData主要用作普通scala.xml.XML对象:

scala> val x = "<foo><bar>aaa<![CDATA[<111/>]]>bbb</bar><![CDATA[<bar/>]]></foo>"
x: String = <foo><bar>aaa<![CDATA[<111/>]]>bbb</bar><![CDATA[<bar/>]]></foo>

scala> XMLLoaderWithCData.loadString(x)
res0: scala.xml.Elem = <foo><bar>aaa<![CDATA[<111/>]]>bbb</bar><![CDATA[<bar/>]]></foo>

此实现当然非常脆弱,取决于Scala库的实现细节,因此可能会在将来更新的情况下中断。

答案 1 :(得分:1)

var a = XML.loadString(xmlString)
var cdata=(a \\ "tagwithCdata").text
var b=  XML.loadString(cdata)

现在您可以将b解析为XML节点。