2014-09-16 2 views
18

У меня есть XML-файл, который хранится как документ DOM, и я бы хотел его распечатать на консоли, желательно без использования внешней библиотеки. Я знаю, что этот вопрос задавался несколько раз на этом сайте, однако ни один из предыдущих ответов не работал для меня. Я использую java 8, так, возможно, это где мой код отличается от предыдущих вопросов? Я также попытался установить трансформатор вручную, используя код, найденный в Интернете, однако это просто вызвало ошибку not found.Довольно печатать XML в java 8

Вот мой код, который в настоящее время выводит каждый элемент xml на новую строку слева от консоли.

import java.io.*; 
import javax.xml.parsers.*; 
import javax.xml.transform.*; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 

import org.w3c.dom.Document; 
import org.xml.sax.InputSource; 
import org.xml.sax.SAXException; 


public class Test { 
    public Test(){ 
     try { 
      //java.lang.System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.xsltc.trax.TransformerFactoryImpl"); 

      DocumentBuilderFactory dbFactory; 
      DocumentBuilder dBuilder; 
      Document original = null; 
      try { 
       dbFactory = DocumentBuilderFactory.newInstance(); 
       dBuilder = dbFactory.newDocumentBuilder(); 
       original = dBuilder.parse(new InputSource(new InputStreamReader(new FileInputStream("xml Store - Copy.xml")))); 
      } catch (SAXException | IOException | ParserConfigurationException e) { 
       e.printStackTrace(); 
      } 
      StringWriter stringWriter = new StringWriter(); 
      StreamResult xmlOutput = new StreamResult(stringWriter); 
      TransformerFactory tf = TransformerFactory.newInstance(); 
      //tf.setAttribute("indent-number", 2); 
      Transformer transformer = tf.newTransformer(); 
      transformer.setOutputProperty(OutputKeys.METHOD, "xml"); 
      transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 
      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); 
      transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
      transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
      transformer.transform(new DOMSource(original), xmlOutput); 
      java.lang.System.out.println(xmlOutput.getWriter().toString()); 
     } catch (Exception ex) { 
      throw new RuntimeException("Error converting to String", ex); 
     } 
    } 

    public static void main(String[] args){ 
     new Test(); 
    } 

} 

ответ

9

Я думаю, что проблема связана с пустыми текстовыми узлами (то есть текстовые узлы только с пробелами) в исходном файле. Вы должны попытаться программно удалить их сразу после разбора, используя следующий код. Если вы их не удалите, то Transformer сохранит их.

original.getDocumentElement().normalize(); 
XPathExpression xpath = XPathFactory.newInstance().newXPath().compile("//text()[normalize-space(.) = '']"); 
NodeList blankTextNodes = (NodeList) xpath.evaluate(original, XPathConstants.NODESET); 

for (int i = 0; i < blankTextNodes.getLength(); i++) { 
    blankTextNodes.item(i).getParentNode().removeChild(blankTextNodes.item(i)); 
} 
+0

Thats perfect! веселит. – Hungry

-2

Создать XML-файл:

new FileInputStream("xml Store - Copy.xml") ;// result xml file format incorrect ! 

так, что, когда анализировать содержимое данного источника входного сигнала в качестве документа XML и возвращает новый объект DOM.

Document original = null; 
... 
original.parse("data.xml");//input source as an XML document 
3

Это работает на Java 8:

public static void main (String[] args) throws Exception { 
    String xmlString = "<hello><from>ME</from></hello>"; 
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 
    Document document = documentBuilder.parse(new InputSource(new StringReader(xmlString))); 
    pretty(document, System.out, 2); 
} 

private static void pretty(Document document, OutputStream outputStream, int indent) throws Exception { 
    TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
    Transformer transformer = transformerFactory.newTransformer(); 
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
    if (indent > 0) { 
     transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
     transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", Integer.toString(indent)); 
    } 
    Result result = new StreamResult(outputStream); 
    Source source = new DOMSource(document); 
    transformer.transform(source, result); 
} 
+0

Хммм, это также работает для меня, поэтому я думаю, проблема должна быть в том, как я читаю xml-файл. – Hungry

+4

Предупреждение. Это решение работает только в том случае, если в исходном xml уже нет (частично) отступом или содержат новые строки. То есть, он будет работать на « ME», но не для « \ п ME \ п» – Espinosa

+1

Для случайных читателей, вот это решение для @ предупреждения Эспиноса: http://stackoverflow.com/ a/33541820/363573 – Stephan

2

Я написал simple class для удаления пробелов в документах, - поддерживает командную строку и не использует DOM/XPath.

Edit: Давай думать об этом, проект также содержит довольно-принтер, который обрабатывает существующие пробелы:

PrettyPrinter prettyPrinter = PrettyPrinterBuilder.newPrettyPrinter().ignoreWhitespace().build(); 
35

В ответ на комментарий Эспиноса, здесь является решение, когда "исходный XML не является уже (частично) отступом или содержать новые строки ".

фон

Выдержка из статьи (см Ссылки ниже) вдохновляя это решение:

на основе спецификации DOM, пробельные символы вне тегов являются вполне действительными и они правильно сохранились. Чтобы удалить их, мы можем использовать нормализованное пространство XPath, чтобы найти все узлы пробелов и сначала удалить их.

Java Code

public static String toPrettyString(String xml, int indent) { 
    try { 
     // Turn xml string into a document 
     Document document = DocumentBuilderFactory.newInstance() 
       .newDocumentBuilder() 
       .parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8")))); 

     // Remove whitespaces outside tags 
     document.normalize(); 
     XPath xPath = XPathFactory.newInstance().newXPath(); 
     NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']", 
                 document, 
                 XPathConstants.NODESET); 

     for (int i = 0; i < nodeList.getLength(); ++i) { 
      Node node = nodeList.item(i); 
      node.getParentNode().removeChild(node); 
     } 

     // Setup pretty print options 
     TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
     transformerFactory.setAttribute("indent-number", indent); 
     Transformer transformer = transformerFactory.newTransformer(); 
     transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
     transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 
     transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 

     // Return pretty print xml string 
     StringWriter stringWriter = new StringWriter(); 
     transformer.transform(new DOMSource(document), new StreamResult(stringWriter)); 
     return stringWriter.toString(); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

Пример использования

String xml = "<root>" + // 
      "\n " + // 
      "\n<name>Coco Puff</name>" + // 
      "\n  <total>10</total> </root>"; 

System.out.println(toPrettyString(xml, 4)); 

Выход

<root> 
    <name>Coco Puff</name> 
    <total>10</total> 
</root> 

Ссылка

+0

Это на самом деле очень похоже на код, который я закончил с помощью :). – Hungry

+1

@ btrs20 Разница зависит от удаления пробелов. – Stephan

+1

Я закончил делать что-то подобное, просто рекурсия, ища только пробелы только текстовые узлы, без xpath. Ваш код короче. Хороший пример продвинутого XPath. Благодарю. – Espinosa

0

Я не понравился ни один из решений общего форматирования XML, потому что все они снимают больше, чем 1 раз подряд новой линии символ (по какой-то причине удаление пробелов/вкладок и удаление новых символов строки неразделимы ...). Вот мое решение, которое было на самом деле сделали для XHTML, но должен сделать работу с XML, а также:

public String GenerateTabs(int tabLevel) { 
    char[] tabs = new char[tabLevel * 2]; 
    Arrays.fill(tabs, ' '); 

    //Or: 
    //char[] tabs = new char[tabLevel]; 
    //Arrays.fill(tabs, '\t'); 

    return new String(tabs); 
} 

public String FormatXHTMLCode(String code) { 
    // Split on new lines. 
    String[] splitLines = code.split("\\n", 0); 

    int tabLevel = 0; 

    // Go through each line. 
    for (int lineNum = 0; lineNum < splitLines.length; ++lineNum) { 
    String currentLine = splitLines[lineNum]; 

    if (currentLine.trim().isEmpty()) { 
     splitLines[lineNum] = ""; 
    } else if (currentLine.matches(".*<[^/!][^<>]+?(?<!/)>?")) { 
     splitLines[lineNum] = GenerateTabs(tabLevel) + splitLines[lineNum]; 

     ++tabLevel; 
    } else if (currentLine.matches(".*</[^<>]+?>")) { 
     --tabLevel; 

     if (tabLevel < 0) { 
     tabLevel = 0; 
     } 

     splitLines[lineNum] = GenerateTabs(tabLevel) + splitLines[lineNum]; 
    } else if (currentLine.matches("[^<>]*?/>")) { 
     splitLines[lineNum] = GenerateTabs(tabLevel) + splitLines[lineNum]; 

     --tabLevel; 

     if (tabLevel < 0) { 
     tabLevel = 0; 
     } 
    } else { 
     splitLines[lineNum] = GenerateTabs(tabLevel) + splitLines[lineNum]; 
    } 
    } 

    return String.join("\n", splitLines); 
} 

Это делает один предположение: что нет <> символов для тех, которые содержат XML/XHTML, за исключением теги.

+1

этот фрагмент неполный, так как переменная codeGenerator не может быть разрешена. это соответствующий класс, написанный в java? поскольку имена методов java имеют другое соглашение об именах. – benez

+0

@benez Извините, и спасибо, что сообщили мне. Я не понимал, что используется внешний код. Попытайтесь, я думаю, это сработает; не может проверить его прямо сейчас. – Andrew

Смежные вопросы