2012-05-14 5 views
6

결과 집합을 XML 파일로 변환하려고합니다. 먼저 직렬화에이 예제를 사용했습니다.Java DOM 문서의 네임 스페이스 및 접두사 설정

이 작업을 한 후에 XML 파일의 유효성을 검사하려고 시도했지만 몇 가지 경고가있었습니다. doctype이없는 것에 대한 하나. 그래서 이것을 구현하는 또 다른 방법을 시도했습니다. Transformer 클래스를 발견했습니다. 이 클래스는 인코딩, doctype 등을 설정할 수있게 해준다.

이전 구현은 자동 네임 스페이스 수정을 지원한다. 다음은 그렇지 않습니다.

private static Document toDocument(ResultSet rs) throws Exception { 
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
    factory.setNamespaceAware(true); 
    DocumentBuilder builder = factory.newDocumentBuilder(); 
    Document doc = builder.newDocument(); 

    URL namespaceURL = new URL("http://www.w3.org/2001/XMLSchema-instance"); 
    String namespace = "xmlns:xsi="+namespaceURL.toString(); 

    Element messages = doc.createElementNS(namespace, "messages"); 
    doc.appendChild(messages); 

    ResultSetMetaData rsmd = rs.getMetaData(); 
    int colCount = rsmd.getColumnCount(); 

    String attributeValue = "true"; 
    String attribute = "xsi:nil"; 

    rs.beforeFirst(); 

    while(rs.next()) { 
     amountOfRecords = 0; 
     Element message = doc.createElement("message"); 
     messages.appendChild(message); 

     for(int i = 1; i <= colCount; i++) { 

      Object value = rs.getObject(i); 
      String columnName = rsmd.getColumnName(i); 

      Element messageNode = doc.createElement(columnName); 

      if(value != null) { 
       messageNode.appendChild(doc.createTextNode(value.toString())); 
      } else { 
       messageNode.setAttribute(attribute, attributeValue); 
      } 
      message.appendChild(messageNode); 
     } 
     amountOfRecords++; 
    } 
    logger.info("Amount of records archived: " + amountOfRecords); 

    TransformerFactory tff = TransformerFactory.newInstance(); 
    Transformer tf = tff.newTransformer(); 
    tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 
    tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
    tf.setOutputProperty(OutputKeys.INDENT, "yes"); 

    BufferedWriter bf = createFile(); 
    StreamResult sr = new StreamResult(bf); 
    DOMSource source = new DOMSource(doc); 
    tf.transform(source, sr); 

    return doc; 
} 

이전 구현을 테스트하는 동안 TransformationException이 발생했습니다 : 접두사 'xsi'의 네임 스페이스가 선언되지 않았습니다. 보시다시피 내 문서의 루트 요소에 xsi 접두사가있는 네임 스페이스를 추가하려고했습니다. 이것을 테스트 한 후에도 예외가 발생했습니다. 네임 스페이스와 접두어를 올바르게 설정하는 방법은 무엇입니까?

편집 : 첫 번째 구현에서 또 다른 문제는 XML 문서의 마지막 요소에 마지막 세 개의 닫는 태그가 없다는 것입니다.

답변

4

루트 노드에 네임 스페이스 선언을 추가하지 않았습니다. 네임 스페이스에서 루트 노드를 선언했는데 완전히 다른 두 가지 일이 생겼다. DOM을 만들 때 모든 관련 노드에서 네임 스페이스를 참조해야합니다. 즉, 속성을 추가 할 때 속성을 정의해야합니다 (예 : setAttributeNS).

사이드 노트 : XML 네임 스페이스는 URL처럼 보이지만 실제로는 그렇지 않습니다. 여기 URL 클래스를 사용할 필요가 없습니다.

+1

고마워, 이제 작동 중입니다. 매일 같이 새로운 것을 배웠습니다. – TrashCan

27

namespaceAware 문서에 노드를 설정하는 올바른 방법은 사용하는 것입니다 :

rootNode.createElementNS("http://example/namespace", "PREFIX:aNodeName"); 

그래서 당신은 자신 만의 접두어로 "PREFIX"를 대체 노드의 이름으로 "aNodeName"를 대체 할 수 있습니다. 그렇지 않으면

documentBuilderFactory.setNamespaceAware(true) 

당신이하지 않습니다

rootNode.setAttribute("xmlns:PREFIX", "http://example/namespace"); 

하는 설정되어 있는지 확인하십시오 : 각 노드가 당신과 같이 루트 노드의 속성과 네임 스페이스를 정의 할 수 있습니다 자신의 네임 스페이스 선언을 가진 것을 방지하려면 네임 스페이스 인식.

+0

+1,'setNamespaceAware'를 호출 할 필요는 없었습니다. 이 함수에 대한 문서는 구문 분석과 관련이 있음을 나타냅니다. –

+1

접두어를 동적으로 설정할 수있는'setPrefix (접두어);'메소드가 있음에 유의하십시오. –

5

setAttribute를 사용하여 xmlns-prefix를 설정하는 것은 잘못된 것입니다. DOM에 서명하고 싶다면 setAttributeNS를 사용해야합니다. element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

+0

차이점을 발견 한 구체적인 예는 무엇입니까? DOM을 파일로 변환 할 때 setAttribute 또는 setAttributeNS를 사용하면 동일한 출력이 제공됩니다. 변환으로 인해 수정되는 런타임 DOM에 약간의 차이가 있습니까? – JBert

관련 문제