Как проанализировать встроенный / смешанный контент xml элементов в java с DOM - PullRequest
0 голосов
/ 08 января 2020

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

В настоящее время я застрял, пытаясь разобрать что-то похожее на это:

<poem>
    <line>Hey diddle, diddle 
        <i>the cat</i> and the fiddle.
    </line>
</poem>

Это не факт xml, но реальный не выглядит намного хуже, поэтому я написал это вместо (та же идея, я думаю)

Я пытаюсь получить вывод примерно так:

Element : line
    text : Hey diddle, diddle
    element: i
        text: the cat
    text: and the fiddle.
------------------------ 
OR
------------------------ 

line:   Hey diddle, diddle
    i: the cat
    and the fiddle

Мой код на данный момент выглядит так:

public class parsingWithDOM {

    public static void main(String[] args) {
        File xml = new File("/Users.../xmlTest.xml");
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(xml);

            NodeList nList = doc.getElementsByTagName("line");
            Node l = nList.item(0);
            if (l.getNodeType() == Node.ELEMENT_NODE) {
                Element line = (Element) l;
                System.out.println(line.getTagName()  + ": " + line.getTextContent());
                NodeList lineList = line.getChildNodes();
                for (int i = 0; i < lineList.getLength(); i++) {
                    Node node = lineList.item(i);
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        Element lineElement = (Element) node;
                        System.out.println(lineElement.getTagName() + ": " + lineElement.getTextContent());
                    }
                }
            }

        } catch (IOException | ParserConfigurationException | DOMException | SAXException e) {
            System.out.println(e.getMessage());
        }

    }
}

В любом случае, я получаю следующий вывод (не совсем то, что я ищу)

line: Hey diddle, diddle the cat and the fiddle.

i: the cat

Любая помощь будет очень ценится ?

Ответы [ 3 ]

1 голос
/ 09 января 2020

Есть много задач, которые намного проще выполнить в XSLT, чем в Java / DOM, и это одна из них. Вот решение с использованием XSLT 3.0.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:f="http://local/"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:output method="text" />
  <xsl:strip-space elements="*"/>

  <xsl:template match="*">
    <xsl:text>{f:indent(.)}ELEMENT {name()}</xsl:text>
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:text>{f:indent(.)}{.}</xsl:text>
  </xsl:template>

  <xsl:function name="f:indent" as="xs:string">
      <xsl:param name="node" as="node()"/>
      <xsl:sequence select="'&#xa;' || string-join((1 to count($node/ancestor::*))!'__')"/>
  </xsl:function>

</xsl:stylesheet>

Выходное значение равно

ELEMENT poem
__ELEMENT line
____text: Hey diddle, diddle 

____ELEMENT i
______text: the cat
____text: and the fiddle.

, и вы можете увидеть его в действии на

https://xsltfiddle.liberty-development.net/gWEaSuR/1

Чтобы рассказать вам об этом:

  • xsl:output говорит, что вы хотите вывод текста, а не XML или HTML

  • xsl:strip-space говорит, что игнорирует текстовые узлы только для пробелов во входных данных

  • Существует два правила xsl:template, одно для элементов и одно для текстовых узлов

  • Оба из них вызывают функцию f:indent, которая генерирует отступ в соответствии с глубиной узла в дереве (определяется путем подсчета предков)

Большинство из работа в этой таблице стилей дает правильное форматирование вывода (навигация ввода сама о себе заботится). Я использовал подчеркивания, а не пробелы в выводе, чтобы вы могли видеть разницу между пробелами, полученными из ввода, и пробелами, генерируемыми таблицей стилей.

JDK имеет встроенный процессор XSLT 1.0, но XSLT 3.0 имеет много дополнительных функций, и для этого вы захотите установить Saxon. Оба процессора могут быть легко вызваны из Java приложений.

1 голос
/ 08 января 2020

Вы можете сделать это следующим образом, используя методы getFirstChild(), getNextSibling() и getParentNode() для навигации по дереву DOM:

int level = 0;
Node node = doc.getDocumentElement();
while (node != null) {
    // Process node
    if (node.getNodeType() == Node.ELEMENT_NODE) {
        System.out.println("  ".repeat(level) + "Element: \"" + node.getNodeName() + "\"");
    } else if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE) {
        String text = node.getNodeValue()
                .replace("\r", "\\r")
                .replace("\n", "\\n")
                .replace("\t", "\\t");
        System.out.println("  ".repeat(level) + "Text: \"" + text + "\"");
    }

    // Advance to next node
    if (node.getFirstChild() != null) {
        node = node.getFirstChild();
        level++;
    } else {
        while (node.getNextSibling() == null && node.getParentNode() != null) {
            node = node.getParentNode();
            level--;
        }
        node = node.getNextSibling();
    }
}

Код использует метод Java 11+ repeat​(int count) для отступа текста. Для более ранних версий Java используйте для этого другой механизм.

Выход

Element: "poem"
  Text: "\n    "
  Element: "line"
    Text: "Hey diddle, diddle \n        "
    Element: "i"
      Text: "the cat"
    Text: " and the fiddle.\n    "
  Text: "\n"
0 голосов
/ 08 января 2020

Ниже код должен go согласно вашему требованию:

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class ParsingWithDOM {

    public static void main(String[] args) {
        File xml = new File("sample.xml");
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(xml);

            StringBuilder sb_inner = new StringBuilder();

            NodeList nList = doc.getElementsByTagName("line");
            Node l = nList.item(0);
            if (l.getNodeType() == Node.ELEMENT_NODE) {
                Element line = (Element) l;

                String outer = line.getTagName()  + ": " + line.getTextContent();

                NodeList lineList = line.getChildNodes();
                for (int i = 0; i < lineList.getLength(); i++) {
                    Node node = lineList.item(i);
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        Element lineElement = (Element) node;
                        sb_inner.append(lineElement.getTagName() + ": " + lineElement.getTextContent()).append("\n");
                    }
                }

                String sub = sb_inner.toString();
                String []formatter = sub.split("\n");
                for(int i=0; i< formatter.length; i++) {
                    outer = outer.replace(formatter[i].split(":")[1].trim(), 
                    formatter[i]+"\n");
                }


                System.out.println(outer);

            }

        } catch (IOException | ParserConfigurationException | DOMException | SAXException e) {
            System.out.println(e.getMessage());
        }

    }
}
...