2014-11-04 10 views
1

JDOM 1.0에서 JDOM2로 업데이트하려고했습니다.JDOM2의 XMLOutputter가 속성 이름 (namespace-part)을 자르지 못하게하는 방법은 무엇입니까?

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
org.w3c.dom.Document doc = dbFactory.newDocumentBuilder().newDocument(); 
doc.setXmlVersion("1.0"); 

Element root = doc.createElement("Document"); 

root.setAttribute("xmlns", "urn:iso:foo"); 
root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd"); 
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
doc.appendChild(root); 

Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("testxml.xml"), "UTF8")); 
DOMBuilder builder = new DOMBuilder(); 
Document jdoc = builder.build(doc); 
XMLOutputter fmt = new XMLOutputter(); 
fmt.setFormat(Format.getPrettyFormat()); 
fmt.output(jdoc, out); 

이 XML 파일을 생성합니다 : JDOM 1.0이 코드에서 내가 JDOM2를 사용하는 경우

<?xml version="1.0" encoding="UTF-8"?> 
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:foo bar.xsd" /> 

, 속성 xsi:schemaLocationschemaLocation로 변경됩니다 (그리고 XML은 모양) :

<?xml version="1.0" encoding="UTF-8"?> 
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="urn:iso:foo bar.xsd" /> 

xsi:을 JDOM2에 보관할 수있는 방법이 있습니까? 그것 없이는 생성 된 XML을 처리하는 시스템이 그것을 읽을 수 없다. this이 같은 질문인지 확실하지 않습니다.

+1

.... 주'그 root'는 DOM이 아닌 JDOM 요소이며, JDOM하지 않습니다 이러한 불법 이름으로 속성을 설정할 수 있습니다. 왜 JDOM 문서로 직접 문서를 만들지 않고 이런 식으로 일을하고 있습니까? – rolfl

+0

특별한 이유가 없습니다. 레거시 코드의 무리. 코드의 일부 주석에 따르면 JDOM은 XML을 형식화하는 데만 사용되는 것처럼 보입니다. JDOM 1.0 덕분에 잘 작동했습니다. 힌트를 가져 주셔서 감사합니다! – Roland

+0

유스 케이스를 찾고 있는데 DOMBuilder에서 속성 네임 스페이스를 선택하지 않은 버그를 발견했을 수 있습니다. 내가 그걸 확인하기 전에 오늘 일을 끝내기를 기다려야 할 것 같다. 당신이 가지고있는 용도는 다소 이례적입니다. 그냥 말해. – rolfl

답변

2

JDOM은 네임 스페이스 인식 DOM 구현을 사용하여 JDOM 문서를 작성해야합니다.

나는이 점을 설명하기 위해 함께 다음 코드를 넣어 가지고 :

import java.io.ByteArrayOutputStream; 
import java.io.OutputStream; 
import java.io.OutputStreamWriter; 
import java.io.StringReader; 

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.transform.OutputKeys; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 

import org.jdom2.Document; 
import org.jdom2.input.DOMBuilder; 
import org.jdom2.output.Format; 
import org.jdom2.output.XMLOutputter; 
import org.w3c.dom.Element; 
import org.xml.sax.InputSource; 


public class DOMvsJDOM { 

    private static org.w3c.dom.Document buildDOM(String xml) throws Exception { 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     dbf.setNamespaceAware(true); 
     dbf.setValidating(false); 
     dbf.setExpandEntityReferences(false); 
     DocumentBuilder db = dbf.newDocumentBuilder(); 
     StringReader sr = new StringReader(xml); 
     InputSource is = new InputSource(sr); 
     return db.parse(is); 
    } 

    public static void printDocument(org.w3c.dom.Document doc, OutputStream out) throws Exception { 
     TransformerFactory tf = TransformerFactory.newInstance(); 
     Transformer transformer = tf.newTransformer(); 
     transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); 
     transformer.setOutputProperty(OutputKeys.METHOD, "xml"); 
     transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
     transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
     transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 

     transformer.transform(new DOMSource(doc), 
      new StreamResult(new OutputStreamWriter(out, "UTF-8"))); 
    } 

    private static void parseUsingJDOM(org.w3c.dom.Document doc) throws Exception { 
//  Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("testxml.xml"), "UTF8")); 
     DOMBuilder builder = new DOMBuilder(); 
     Document jdoc = builder.build(doc); 
     XMLOutputter fmt = new XMLOutputter(); 
     fmt.setFormat(Format.getPrettyFormat()); 
     fmt.output(jdoc, System.out); 
    } 

    public static void main(String[] args) throws Exception { 
     DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
     org.w3c.dom.Document doc = dbFactory.newDocumentBuilder().newDocument(); 
     doc.setXmlVersion("1.0"); 

     Element root = doc.createElement("Document"); 

     root.setAttribute("xmlns", "urn:iso:foo"); 
     root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd"); 
     root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
     doc.appendChild(root); 

     printDocument(doc, System.out); 

     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     printDocument(doc, baos); 

     System.out.println("JDOM Using captured"); 
     parseUsingJDOM(doc); 

     String xml = new String(baos.toByteArray()); 
     doc = buildDOM(xml); 

     System.out.println("JDOM Using parsed"); 
     parseUsingJDOM(doc); 

    } 
} 

참고 수행하는 코드를 THIE 무엇을, 수동으로 그 때의 DOM에서 JDOM을 구축 출력, 출력, DOM을 구축 할 것을 DOM을 문자열로 출력하고 DOM을 String으로 다시 구문 분석 한 다음 다시 파싱 한 XML에서 JDOM을 빌드합니다.

<?xml version="1.0" encoding="UTF-8"?> 
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:foo bar.xsd"/> 
JDOM Using captured 
<?xml version="1.0" encoding="UTF-8"?> 
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="urn:iso:foo bar.xsd" /> 
JDOM Using parsed 
<?xml version="1.0" encoding="UTF-8"?> 
<Document xmlns="urn:iso:foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:foo bar.xsd" /> 

결론은 DOM이 생성된다 :

는 출력 (I 실제 DOM 문자열이 자신의 라인에 XML 선언을하기 위해 수동으로 출력에 줄 바꿈을 넣어)입니다 출력은 기술적으로 "네임 스페이스 인식"이 아니므로 JDOM 2.0의 기대치를 충족시키지 못합니다. 대신 네임 스페이스 인식 버전을 사용하는 경우

root.setAttribute("xmlns", "urn:iso:foo"); 
root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd"); 
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 

:

지금, 당신은 속성을 설정하려면 다음 코드를 사용

root.setAttribute("xmlns", "urn:iso:foo"); 
    root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
    root.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", "urn:iso:foo bar.xsd"); 
    doc.appendChild(root); 

다음 JDOM은 그것을 바로 얻을 것이다 .

위와 같은 이유 때문에 JDOM이 구문 분석이 네임 스페이스 인식 방식으로 수행되기 때문에 위의 구문 분석 된 버전에서 작동합니다.

따라서 JDOM은 DOM 컨텐츠를 처리 할 때 DOM 컨텐츠가 XML 이름 공간 인식 형식이어야한다는 요구 사항이 있습니다. 내 DOM 내용이 모두 네임 스페이스를 인식하기 때문에 내 테스트가 모두 작동하는 이유입니다.

아쉽게도 실제 문제가 해결되지 않아 .... 단지 설명합니다.

JDOM2 이 경우에는이이어야하며이 경우에는 JDOM 1.x와 호환되어야하며 호환되지 않는 것이 문제입니다. JDOM2는 '옳은'일을하고 있지만 '틀린'일을 또한 수행해야하며 DOM에 정의 된 속성에 대한 네임 스페이스를 찾아야한다.

내가 이것을 추적하는 문제 (138)을 만들었습니다 : 현재 DOM과 JDOM 내용의 불편한 혼합이 https://github.com/hunterhacker/jdom/issues/138

0

rolfl의 힌트에 따르면, 한 가지 방법은 DOM과 JDOM 컨텐츠를 혼합하여 만든 파일로 XML을 저장 만 DOM을 사용하지 않는 것입니다 :

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
Document doc = dbFactory.newDocumentBuilder().newDocument(); 
doc.setXmlVersion("1.0"); 

Element root = doc.createElement("Document"); 

root.setAttribute("xmlns", "urn:iso:foo"); 
root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd"); 
root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
doc.appendChild(root); 

TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
transformerFactory.setAttribute("indent-number", 2); 
Transformer transformer = transformerFactory.newTransformer(); 
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
DOMSource source = new DOMSource(doc); 
StreamResult xmlfile = new StreamResult(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("testxml.xml"), "UTF8"))); 
transformer.transform(source, xmlfile); 

그러나 이것은 완전히 유효하지 않습니다 대답은 JDOM2를 사용하여 작업을 완료하는 방법입니다.

+0

이 문제는 기술적으로 DOM의 네임 스페이스가 일관성없이 사용된다는 것을 지적하기 위해'root.setAttribute ("xsi : schemaLocation", "urn : iso : foo bar.xsd"); .setAttributeNS ("http://www.w3.org/2001/XMLSchema-instance", "xsi : schemaLocation", "urn : iso : foo bar.xsd"); – rolfl