Как распарсить xml с повторяющимися тэгами в List?

Рейтинг: 0Ответов: 1Опубликовано: 01.04.2023

Имеется xml с повторяющимися тэгами, примерно такой:

public class Main {
public static void main(String[] args) throws ParserConfigurationException {
    String xmlString = "<abc:Body>\n" +
            "   <abc:AssyData>\n" +
            "     <abc:Order>1</abc:Order>\n" +
            "     <abc:Name>A</abc:Name>\n" +
            "   </abc:AssyData>\n" +
            "   <abc:AssyData>\n" +
            "     <abc:Order>2</abc:Order>\n" +
            "     <abc:Name>B</abc:Name>\n" +
            "   </abc:AssyData>\n" +
            "   <abc:AssyData>\n" +
            "     <abc:Order>3</abc:Order>\n" +
            "     <abc:Name>C</abc:Name>\n" +
            "   </abc:AssyData>\n" +
            "</abc:Body>";
    List<String> orders = new ArrayList<String>();
    List<String> names = new ArrayList<String>();
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
        dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = convertStringToXml(xmlString);//IDOC это мой XML на диске
        doc.getDocumentElement().normalize();
        NodeList list = doc.getElementsByTagName("abc:Body");
        for (int temp = 0; temp < list.getLength(); temp++) {
            Node node = list.item(temp);
            if(node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                orders.add(element.getElementsByTagName("abc:Order").item(0).getTextContent());
                names.add(element.getElementsByTagName("abc:Name").item(0).getTextContent());
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println(orders);
    System.out.println(names);

}
private static Document convertStringToXml(String xmlString) {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
        dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        DocumentBuilder builder = dbf.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
        return doc;
    } catch (ParserConfigurationException | IOException | SAXException e) {
        throw new RuntimeException(e);
    }
}
}

На выходе получаю только значения

order = 1;
name = A;

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

List<String> orders = [1,2,3]
List<String> names = [A,B,C]

И так далее, днина документа может быть разной. Помогите плиз) (java ee 5, лямбд, стримов нет)

Ответы

▲ 0Принят

Используйте List::add для добавления в соответствуюшие списки, для этого не нужно ни лямбд, ни стримов.
Также, вероятно, имеет смысл не разбивать данные по отдельным спискам, а использовать объект с двумя указанными полями типа такого AssyData(String name, String order) и иметь отдельный список для него.

Главная ошибка кода, представленного в вопросе, в том, что в переменную list вычитывается единственный корневой элемент документа abc:Body (разумеется, длина такого списка равна 1), а не список соответствующих элементов AssyData длиной 3.
Также были проблемы с компиляцией кода из-за неправильных названий методов Document::getElementsByTagName; Element::getElementsByTagName; Node::getTextContent

// ...
NodeList list = doc.getElementsByTagName("abc:AssyData"); // вместо abc:Body
List<AssyData> data = new ArrayList<AssyData>(); // diamond operator since Java 7
for (int temp = 0; temp < list.getLength(); temp++) {
    Node node = list.item(temp);
    if (node.getNodeType() == Node.ELEMENT_NODE) {
        Element element = (Element) node;
        order = element.getElementsByTagName("abc:Order").item(0).getTextContent();
        name = element.getElementsByTagName("abc:Name").item(0).getTextContent();

        // просто добавьте элементы в нужные списки
        orders.add(order);
        names.add(name);
        data.add(new AssyData(name, order));
    }
}
System.out.println(orders);
System.out.println(names);