2013-08-18 93 views
3

解析Groovy中的XML應該是一件小事,但我總是遇到問題。使用命名空間和實體解析Groovy中的XML

我想解析字符串是這樣的:

<html> 
<p> 
This&nbsp;is a <span>test</span> with <b>some</b> formattings.<br /> 
And this has a <ac:special>special</ac:special> formatting. 
</p> 
</html> 

當我這樣做的標準方式new XmlSlurper().parseText(body),解析器抱怨的&nbsp實體。我在這樣的情況下,祕密武器就是使用tagsoup:

def parser = new org.ccil.cowan.tagsoup.Parser() 
def page = new XmlSlurper(parser).parseText(body) 

但現在<ac:sepcial>標籤將由解析器立刻關閉 - 在special文本將不會在導致DOM在此標籤內。甚至當我禁用命名空間功能:

def parser = new org.ccil.cowan.tagsoup.Parser() 
parser.setFeature(parser.namespacesFeature,false) 
def page = new XmlSlurper(parser).parseText(body) 

另一種方法是使用標準的解析器和添加的doctype像這樣的:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

這似乎爲我的大部分文件的工作,但解析器獲取dtd並處理它需要很長時間。

任何好主意如何解決這個問題?

PS:這裏是一些示例代碼一起玩:

@Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='0.9.7') 
def processNode(node) { 
    def out = new StringBuilder("") 
    node.children.each { 
     if (it instanceof String) { 
      out << it 
     } else { 
      out << "<${it.name()}>${processNode(it)}</${it.name()}>" 
     } 
    } 
    return out.toString() 
} 

def body = """<html> 
<p> 
This&nbsp;is a <span>test</span> with <b>some</b> formattings.<br /> 
And this has a <ac:special>special</ac:special> formatting. 
</p> 
</html>""" 

def parser = new org.ccil.cowan.tagsoup.Parser() 
parser.setFeature(parser.namespacesFeature,false) 
def page = new XmlSlurper(parser).parseText(body) 
def out = new StringBuilder("") 
page.childNodes().each { 
    out << processNode(it) 
} 
println out.toString() 
"" 

回答

2

你將不得不決定是否要解析符合標準的,要在DTD路徑,或接受只是一個寬容的解析器什麼。

Tagsoup以我的經驗對後者很好,它很少產生任何問題,所以我很驚訝地看到你對它的處理「特殊」的評論。快速測試還顯示,我無法重現:在你的樣品運行此命令

java net.sf.saxon.Query -x:org.ccil.cowan.tagsoup.Parser -s:- -qs:. !encoding=ASCII !indent=yes 

的時候,我接到這個結果

<?xml version="1.0" encoding="ASCII"?> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml"> 
    <body> 
     <p> 
    This&#xa0;is a <span>test</span> with <b>some</b> formattings.<br clear="none"/> 
    And this has a <ac:special xmlns:ac="urn:x-prefix:ac">special</ac:special> formatting. 
    </p> 

    </body> 
</html> 

來自TagSoup 1.2和1.2.1。因此,對我來說,如預期那樣,在「ac:special」標籤內出現「特殊」文本。

至於DTD變體,您可以通過緩存代理來解析DTD,引用本地副本,甚至將DTD減少到您需要的最小值。以下應該足以讓您穿過&nbsp;實體:

<!DOCTYPE DOC[<!ENTITY nbsp "&#160;">]> 
+0

太棒了!它是我使用的tagsoup解析器的版本(0.9.x)... 1.2.1適合我。感謝名單! – rdmueller