Игнорировать escape-символы при разборе XML DOM4J

Java

Опыт проекта, если нужно перепечатать, просьба указать автора: Yuloran (t.cn/EGU6c76)

задний план

При разработке проекта приходится вручную сливать переводы десятков языков в string.xml, что очень мучительно: Копировать, Вставить, Копировать, Вставить, Копировать, Вставить... Люди сходят с ума! Я был вынужден написать инструмент, который автоматически заменяет перевод. Принцип прост: парсить перевод в Excel и заменять в Xml. Парсинг Excel использует jxl.jar, парсинг и модификация Xml использует DOM, одна операция, один день! Я был счастлив, поэтому быстро использовал git diff для проверки сравнения модификаций и увидел что-то нехорошее: «Что за дурак! Это совсем не идеально! Все escape-символы в исходной строке были экранированы! вернуть его? Такие люди, как я, которые превосходны (ленивы) и показывают (ленивы), вообще не могут этого терпеть!" Поэтому в этой статье описано, как использовать DOM4J (разве выше не говорится о парсинге DOM? Почему DOM4J здесь снова Кто это!) XML и игнорировать escape-символы.

Почему бы не использовать ДОМ

Кто сказал, что я не использовал DOM, я использовал DOM, как только придумал! В конце концов, JDK поставляется вместе с ним! Но после его использования пользовательский опыт плохой! Немного о том, как его использовать:

package com.yuloran;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {

        // 1. 解析
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
        Document document = documentBuilder.parse(new InputSource(new InputStreamReader(new FileInputStream("strings.xml"), "UTF-8")));

        // 2. 遍历
        NodeList strings = document.getElementsByTagName("string");
        for (int i = 0; i < strings.getLength(); i++) {
            Node item = strings.item(i);
            System.out.print(String.format("Element:[tag:%s, content:%s] ", item.getNodeName(), item.getTextContent()));
            NamedNodeMap attributes = item.getAttributes();
            for (int j = 0; j < attributes.getLength(); j++) {
                Node attr = attributes.item(j);
                System.out.println(String.format("Attr:[key:%s, value:%s]", attr.getNodeName(), attr.getNodeValue()));
            }
        }

        // 3. 保存
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(new DOMSource(document), new StreamResult("strings_copy.xml"));
    }

}

строки.xml:

strings.xml

Разобрать журнал:

解析日志.png

strings_copy.xml:

strings_copy.png

Проблемы с разбором DOM при сохранении файлов XML:

  • standalone="no" автоматически добавляется в объявление XML-документа, доступ к которому можно получить черезdocument.setXmlStandalone(true);удалить, но тогда отступ не удастся!
  • Новые строки файлов автоматически заменяются новыми строками там, где находится операционная система!

Итак, вместо DOM я использую DOM4J. С DOM4J эти проблемы станут облаками!

Разбор DOM4J

Это очень просто! читать напрямуюОфициальное руководствоВот и все! Я никогда не видел документации по API такой четкой и лаконичной!

Пакет JAR DOM4J и загрузка зависимостей:

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

package com.yuloran;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import java.io.*;
import java.util.List;

public class Main {

    public static void main(String[] args) throws DocumentException, IOException {
        // 1. 解析
        SAXReader reader = new SAXReader();
        Document document = reader.read(new InputSource(new InputStreamReader(new FileInputStream("strings.xml"), "UTF-8")));

        // 2. 遍历
        List<Node> list = document.selectNodes("/resources/string[@name]");
        for (Node node : list) {
            System.out.print(String.format("Element:[tag:%s, content:%s] ", node.getName(), node.getText()));
            System.out.println(String.format("Attr:[name@%s]", node.valueOf("@name")));
        }

        // 3.保存
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("strings_dom4j.xml"), "UTF-8");
        XMLWriter xmlWriter = new XMLWriter(writer);
        // 忽略 Element 对象中的转义字符
        xmlWriter.setEscapeText(false);
        xmlWriter.write(document);
        xmlWriter.close();
    }

}

strings_dom4j.xml:

strings_dom4j.xml

как насчет этого? Посмотрите на этот вывод, в нем нет ничего плохого!

игнорировать escape-символы

На самом деле это проблема синтаксического анализа SAX (Simple Application Interface For Xml).Когда SAX анализирует XML, он автоматически экранирует escape-символы в тексте элемента, так что, когда объект документа, наконец, будет сохранен в виде файла, исходный escape-символы не могут быть записаны.

Исходный файл:

带转义字符的xml.png

Разбор DOM4J и обратная запись:

DOM4J 解析再写回.png

Итак, нам нужно реализовать фильтр, который всякий раз, когда SAX анализирует escape-символ, записывает его как есть:

        reader.setXMLFilter(new XMLFilterImpl() {
            @Override
            public void characters(char[] ch, int start, int length) throws SAXException {
                String text = new String(ch, start, length);
                System.out.println("text is: " + text);

                if (length == 1) {
                    if ((int) ch[0] == 160) {
                        char[] escape = "&#160;".toCharArray();
                        super.characters(escape, 0, escape.length);
                        return;
                    }
                }

                super.characters(ch, start, length);
            }
        });

ПеределкаxmlWriter.setEscapeText(false);Вы можете вывести escape-символы в исходном файле Xml так, как они есть:

        // 3.保存
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("strings_dom4j.xml"), "UTF-8");
        XMLWriter xmlWriter = new XMLWriter(writer);
        xmlWriter.setEscapeText(false);
        xmlWriter.write(document);
        xmlWriter.close();

Результаты теста:

原Xml.png

журнал:

日志.png

strings_dom4j.xml:

strings_dom4j.xml

Другие escape-символы обрабатываются таким же образом. Вы можете поместить управляющие символы, которые будут игнорироваться в файле конфигурации, и прочитать управляющие символы, которые будут игнорироваться, из конфигурации при создании инструментов, что является более гибким.

Суммировать

В этой статье написано только окончательное решение, и процесс изучения этого решения на самом деле довольно сложен. Спрос небольшой, а информации нет.Можно только посмотреть исходный код и угадать интерфейс.В любом случае, я не верю, что такой фреймворк парсинга не выставляет интерфейс для самостоятельной обработки строк пользователями. Разумеется, по-прежнему можно передавать метод character(), но SAXReader не предоставляет интерфейс ContentHandler. найти.