Как удалить лишние строки из файла XML?

Короче говоря; У меня есть много пустых строк, сгенерированных в XML файле, и я ищу способ удалить их как способ наклонения файла. Как я могу это сделать?

Подробное объяснение; В настоящее время у меня есть этот XML файл:

<recent>
  <paths>
    <path>path1</path>
    <path>path2</path>
    <path>path3</path>
    <path>path4</path>
  </paths>
</recent>

И я использую этот код Java для удаления всех тегов и вместо этого добавляю новые:

public void savePaths( String recentFilePath ) {
    ArrayList<String> newPaths = getNewRecentPaths();
    Document recentDomObject = getXMLFile( recentFilePath );  // Get the <recent> element.
    NodeList pathNodes = recentDomObject.getElementsByTagName( "path" );   // Get all <path> nodes.

    //1. Remove all old path nodes :
        for ( int i = pathNodes.getLength() - 1; i >= 0; i-- ) { 
            Element pathNode = (Element)pathNodes.item( i );
            pathNode.getParentNode().removeChild( pathNode );
        }

    //2. Save all new paths :
        Element pathsElement = (Element)recentDomObject.getElementsByTagName( "paths" ).item( 0 );   // Get the first <paths> node.

        for( String newPath: newPaths ) {
            Element newPathElement = recentDomObject.createElement( "path" );
            newPathElement.setTextContent( newPath );
            pathsElement.appendChild( newPathElement );
        }

    //3. Save the XML changes :
        saveXMLFile( recentFilePath, recentDomObject ); 
}

После выполнения этого метода несколько раз я получаю XML файл с правильными результатами, но со многими пустыми строками после тега "paths" и перед первым тегом "path", например:

<recent>
  <paths>





    <path>path5</path>
    <path>path6</path>
    <path>path7</path>
  </paths>
</recent>

Кто-нибудь знает, как это исправить?

------------------------------------------- Изменить: Добавить код getXMLFile (...), saveXMLFile (...).

public Document getXMLFile( String filePath ) { 
    File xmlFile = new File( filePath );

    try {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document domObject = db.parse( xmlFile );
        domObject.getDocumentElement().normalize();

        return domObject;
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

public void saveXMLFile( String filePath, Document domObject ) {
    File xmlOutputFile = null;
    FileOutputStream fos = null;

    try {
        xmlOutputFile = new File( filePath );
        fos = new FileOutputStream( xmlOutputFile );
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
        transformer.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "2" );
        DOMSource xmlSource = new DOMSource( domObject );
        StreamResult xmlResult = new StreamResult( fos );
        transformer.transform( xmlSource, xmlResult );  // Save the XML file.
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    } catch (TransformerException e) {
        e.printStackTrace();
    } finally {
        if (fos != null)
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

Ответ 1

Я смог исправить это, используя этот код после удаления всех старых узлов пути:

while( pathsElement.hasChildNodes() )
    pathsElement.removeChild( pathsElement.getFirstChild() );

Это приведет к удалению всех сгенерированных пустых пространств в файле XML.

Особая благодарность MadProgrammer за комментирование с помощью полезной ссылки, упомянутой выше.

Ответ 2

Во-первых, объяснение того, почему это происходит - что может быть немного не так, поскольку вы не включили код, который используется для загрузки файла XML в объект DOM.

Когда вы читаете XML-документ из файла, пробелы между тегами фактически составляют действительные узлы DOM, в соответствии со спецификацией DOM. Поэтому синтаксический анализатор XML обрабатывает каждую такую последовательность пробелов как узел DOM (типа TEXT);

Чтобы избавиться от этого, есть три подхода, которые я могу придумать:

  • setValidating(true) XML со схемой, а затем используйте setValidating(true) вместе с setIgnoringElementContentWhitespace(true) в DocumentBuilderFactory.

    (Примечание: setIgnoringElementContentWhitespace будет работать только в том случае, если анализатор находится в режиме проверки, поэтому вы должны использовать setValidating(true))

  • Напишите XSL для обработки всех узлов, отфильтровывая узлы TEXT только для пробелов.
  • Для этого используйте код Java: используйте XPath, чтобы найти все узлы TEXT только для пробелов, выполнить итерацию по ним и удалить каждый из своих родительских узлов (используя getParentNode().removeChild()). Нечто подобное может подойти (doc будет вашим объектом документа DOM):

    XPath xp = XPathFactory.newInstance().newXPath();
    NodeList nl = (NodeList) xp.evaluate("//text()[normalize-space(.)='']", doc, XPathConstants.NODESET);
    
    for (int i=0; i < nl.getLength(); ++i) {
        Node node = nl.item(i);
        node.getParentNode().removeChild(node);
    }
    

Ответ 3

Вы можете посмотреть на что-то вроде this, если вам нужно просто "очистить" ваш xml быстро. Тогда у вас может быть такой метод:

public static String cleanUp(String xml) {
    final StringReader reader = new StringReader(xml.trim());
    final StringWriter writer = new StringWriter();
    try {
        XmlUtil.prettyFormat(reader, writer);
        return writer.toString();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return xml.trim();
}

Кроме того, чтобы сравнить различия в проверке anche, если вам это нужно: XMLUnit

Ответ 4

У меня возникла такая же проблема, и я долго не знала, но теперь, после этого вопроса Брэда и его собственного ответа по его собственному вопросу, я выяснил, в чем проблема.

Я должен добавить свой собственный ответ, потому что Брэд один не совсем совершенен, как сказал Исаак:

Я бы не стал большим поклонником слепого удаления дочерних узлов, не зная, что они представляют.

Итак, лучшее "решение" (цитируется, потому что это скорее всего обходное решение):

pathsElement.setTextContent("");

Это полностью удаляет ненужные пустые строки. Это определенно лучше, чем удаление всех дочерних узлов. Брэд, это тоже сработает для вас.

Но это эффект, а не причина, и мы получили, как удалить этот эффект, а не причину.

Причиной является: когда мы вызываем removeChild(), он удаляет это дочерние элементы, но оставляет отступ удаляемого дочернего элемента, а также прерывание строки. И этот indent_and_like_break рассматривается как текстовое содержимое.

Итак, чтобы устранить причину, мы должны выяснить , как удалить дочерний элемент и его отступ. Добро пожаловать в мой вопрос об этом.

Ответ 5

Я использую код ниже:

System.out.println("Start remove textnode");
        i=0;
        while (parentNode.getChildNodes().item(i)!=null) {
            System.out.println(parentNode.getChildNodes().item(i).getNodeName());
            if (parentNode.getChildNodes().item(i).getNodeName().equalsIgnoreCase("#text")) {
                parentNode.removeChild(parentNode.getChildNodes().item(i));
                System.out.println("text node removed");
            }
            i=i+1;

        }

Ответ 6

Несколько замечаний: 1) Когда вы манипулируете XML (удаляя элементы/добавляя новый), я настоятельно рекомендую вам использовать XSLT (а не DOM) 2) Когда вы транслируете XML-документ с помощью XSLT (как и в методе сохранения), установите для OutputKeys.INDENT значение "нет", 3) Для простой последующей обработки вашего xml (удаление пробелов, комментариев и т.д.) Вы можете использовать простой фильтр SAX2

Ответ 7

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringElementContentWhitespace(true);

Ответ 8

Существует очень простой способ избавиться от пустых строк, если используется API обработки DOM (например, DOM4J):

  • поместите текст, который вы хотите сохранить в переменной (т.е. text)
  • установите для текста node значение "" с помощью node.setText("")
  • установите для node текст text с помощью node.setText(text)

et voila! больше нет пустых строк. Другие ответы очень хорошо определяют, как лишние пустые строки в выводе xml на самом деле являются дополнительными узлами текста типа.

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

Надеюсь, что это поможет:)