2011-09-07 54 views
2

我有一個類似XML的文件:解析XML並獲得無約束力的命名空間DOM樹 - Java的

<p>something</p> 
<ac:image> 
    <ri:attachment ri:filename="IMAGE.PNG" /> 
</ac:image> 
<ac:macro ac:name="screenshot"> 
    <ac:default-parameter>IMAGE.ss</ac:default-parameter> 
</ac:macro> 
<p>something</p> 

我需要XSLT模板來改造它 - 我想所有<ac:image><ac:macro ac:name="screenshot">取代。一般來說,解析和轉換格式良好的XML並非常容易。我的情況相當不同。

如您所見,它沒有根元素和XML序言。但它不是一個問題,我可以添加<?xml version="1.0"?>,敷用,如<root>任意元素的內容,以避免異常:

Caused by: org.jdom.input.JDOMParseException: Error on line 1: Content is not allowed in prolog. 

示例XML包含三個命名空間 - 默認情況下,acri。由於代碼將在客戶指定的內容上運行,因此可能會有其他一些我不知道的名稱空間。我不能夠解析XML之前,所有的命名空間綁定,所以我遇到異常:

Caused by: org.xml.sax.SAXParseException: Content is not allowed in prolog. 

我發現某處在互聯網上,SAX解析器能夠解析個XML的模式,它不能解決上命名空間。在默認模式下,您獲得namespace=acelement=macro,而在非名稱空間模式下,您不會獲得名稱空間並且不會獲得element=ac:macro。這是理想的。您只需要在解析器上設置SAX功能:namespaces=false,namespace-prefixes=true

final XMLReader sax = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); 
sax.setFeature("http://xml.org/sax/features/validation", false); 
sax.setFeature("http://xml.org/sax/features/namespaces", false); 
sax.setFeature("http://xml.org/sax/features/namespace-prefixes", true); 
sax.parse(new InputSource(new StringReader(content))); // parse returns void 

它不會拋出任何異常,所以它看起來像XML解析沒有錯誤。但是,我需要一個DOM樹,以便我可以使用XSLT進行轉換。讓我們用JDOM則:

// all classes are org.jdom.* 
final SAXBuilder sax = new SAXBuilder(false); // validate=false 
sax.setFeature("http://xml.org/sax/features/namespaces", false); 
sax.setFeature("http://xml.org/sax/features/namespace-prefixes", true); 
final Document document = sax.build(new StringInputStream(content)); 

不幸的是,我得到一個異常:

Caused by: org.jdom.IllegalNameException: The name "" is not legal for JDOM/XML elements: XML names cannot be null or empty. 
    at org.jdom.Element.setName(Element.java:206) 
    at org.jdom.Element.<init>(Element.java:140) 
    at org.jdom.Element.<init>(Element.java:152) 
    at org.jdom.DefaultJDOMFactory.element(DefaultJDOMFactory.java:138) 
    at org.jdom.input.SAXHandler.startElement(SAXHandler.java:511) 
    at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source) 
    at org.apache.xerces.impl.dtd.XMLDTDValidator.startElement(Unknown Source) 
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source) 
    at org.apache.xerces.impl.XMLDocumentScannerImpl$ContentDispatcher.scanRootElementHook(Unknown Source) 
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) 
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) 
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) 
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) 
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) 
    at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) 
    at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) 
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:453) 
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:770) 
    at com.screensnipe.confluence.macro.XhtmlImageMacroReplacer.replaceImageMacroInText(XhtmlImageMacroReplacer.java:118) 

JDOM抱怨一個非法的標記名稱<>。當然,我沒有這樣的。看起來JDOM在SAXHandler.java中有錯誤:511,應該是element = factory.element(qName);

我也試過XOM。 XOM does not work with "namespaces" feature set to false

我也試過TagSoup庫。我不喜歡它,因爲它搞亂了輸出XML。添加XML prolog和根元素不是問題。混淆命名空間是。

<?xml version="1.0"?> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <body> 
     <p>something</p> 
     <ac:image xmlns:ac="urn:x-prefix:ac"> <!-- :(--> 
      <ri:attachment xmlns:ri="urn:x-prefix:ri" ri:filename="IMAGE.PNG" /> 
     </ac:image> 
     ... 

問題是:如何從我的XML中獲取DOM樹? (Java)不寫我的JDOM版本。我將不勝感激工作解決方案。只需解析並獲取DOM樹。與TagSoup庫一樣,名稱空間沒有被破壞的樹。

或更多以目標爲中心的問題:如何用<ac:macro ac:name="screenshot">替換<ac:image>而不觸及其他標籤? (Java)所有其他標記,名稱空間或其他應該不受影響。 (不建議任何正則表達式)

回答

1

如果您願意進行預處理,如添加周圍的根元素,您還可以查看XML文件中的名稱空間前綴,併爲每個元素添加虛擬聲明他們到你添加的根元素。

然後,您將不需要可以被告知不解析命名空間前綴的解析器。

+1

嗯...不完美的方式,但它很容易,會做的東西。謝謝,upvoted。如果沒有更好的答案,我會接受你的答案。 :) – Nowaker