2012-05-14 5 views
6

Próbuję przekonwertować ResultSet na plik XML. Po raz pierwszy użyłem tego przykładu do serializacji.Ustawianie przestrzeni i przedrostków w dokumencie DOM DOM

import org.w3c.dom.bootstrap.DOMImplementationRegistry; 
import org.w3c.dom.Document; 
import org.w3c.dom.ls.DOMImplementationLS; 
import org.w3c.dom.ls.LSSerializer; 

... 

DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance(); 

DOMImplementationLS impl = 
    (DOMImplementationLS)registry.getDOMImplementation("LS"); 

...  

LSSerializer writer = impl.createLSSerializer(); 
String str = writer.writeToString(document); 

Po wykonaniu tej pracy, próbowałem sprawdzić poprawność mojego pliku XML, było kilka ostrzeżeń. Jedna o braku typu dokumentu. Spróbowałem więc innego sposobu na wdrożenie tego. Natknąłem się na klasy Transformer. Ta klasa pozwala ustawić kodowanie, typ dokumentu itp.

Poprzednia implementacja obsługuje automatyczne instalowanie przestrzeni nazw. Poniższe nie.

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; 
} 

Chociaż testował poprzedni realizację Mam TransformationException Przestrzeń nazw dla przedrostka „xsi” nie został uznany. Jak widać, próbowałem dodać przestrzeń nazw z przedrostkiem xsi do głównego elementu mojego dokumentu. Po przetestowaniu tego nadal mam wyjątek. Jaki jest prawidłowy sposób ustawiania przestrzeni nazw i ich prefiksów?

Edytuj: Kolejny problem z pierwszą implementacją polega na tym, że ostatni element w dokumencie XML nie zawiera ostatnich trzech znaczników zamykających.

Odpowiedz

4

Nie dodano deklaracji przestrzeni nazw w głównym węźle; właśnie zadeklarowałeś węzeł główny w przestrzeni nazw, dwie całkowicie różne rzeczy. Podczas budowania modelu DOM należy odwoływać się do przestrzeni nazw w każdym odpowiednim węźle. Innymi słowy, po dodaniu atrybutu należy zdefiniować jego przestrzeń nazw (np. SetAttributeNS).

Nota boczna: Chociaż przestrzenie nazw XML wyglądają jak adresy URL, tak naprawdę nie są. Nie ma potrzeby używania tutaj klasy adresu URL.

+1

Dzięki, działa. Nauczyłem się czegoś nowego dzisiaj, tak jak każdego dnia. – TrashCan

27

Prawidłowy sposób ustawić węzeł dokumentu namespaceAware jest za pomocą:

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

Więc można zastąpić „przedrostek” z własnego niestandardowego prefiksu i zastąpić „aNodeName” z nazwą węzła. Aby uniknąć konieczności każdy węzeł posiada własną deklarację przestrzeni nazw można zdefiniować jako nazw atrybutów na węźle głównym tak:

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

Pamiętaj, aby ustawić:

documentBuilderFactory.setNamespaceAware(true) 

Inaczej nie masz przestrzeń nazw.

+0

+1, chociaż nie musiałem wywoływać 'setNamespaceAware'. Dokumentacja tej funkcji sugeruje, że jest ona związana z analizą. –

+1

Należy zauważyć, że istnieje metoda 'setPrefix (prefix);', która pozwala na dynamiczne ustawianie prefiksu. –

5

Należy pamiętać, że ustawienie przedrostka xmlns z atrybutem setAttribute jest nieprawidłowe. Jeśli chcesz np. Podpisać DOM, musisz użyć funkcji setAttributeNS: element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

+0

Każdy konkretny przykład, w którym zauważyłeś różnicę? Kiedy przekształcam DOM w plik, użycie funkcji setAttribute lub setAttributeNS daje takie same wyniki. Czy zauważyłeś pewne różnice w DOM środowiska wykonawczego, które transformacja rozwiązuje? – JBert