Как получить данные вложенных объектов XML с помощью SAX - PullRequest
0 голосов
/ 20 октября 2019

У меня есть следующий XML-файл:

<?xml version="1.0" encoding="UTF-8"?>
<restaurants>
    <restaurant>
        <street>Street1</street>
        <title>Restaurant1</title>
        <cuisine>Belorussian</cuisine>
        <hall capacity="per.">10</hall>
        <menu>
            <dish>
                <name>Dish1</name>
                <price currency="dol.">100</price>
            </dish>
            <dish>
                <name>Dish2</name>
                <price currency="dol.">200</price>
            </dish>
            <dish>
                <name>Dish3</name>
                <price currency="dol.">300</price>
            </dish>
        </menu>
    </restaurant>
    <restaurant>
        <street>Street2</street>
        <title>Restaurant2</title>
        <cuisine>Russian</cuisine>
        <hall capacity="per.">20</hall>
        <menu>
            <dish>
                <name>Dish4</name>
                <price currency="dol.">400</price>
            </dish>
            <dish>
                <name>Dish5</name>
                <price currency="dol.">500</price>
            </dish>
            <dish>
                <name>Dish6</name>
                <price currency="dol.">600</price>
            </dish>
        </menu>
    </restaurant>
    <restaurant>
        <street>Street3</street>
        <title>Restaurant3</title>
        <cuisine>Chinese</cuisine>
        <hall capacity="per.">30</hall>
        <menu>
            <dish>
                <name>Dish7</name>
                <price currency="dol.">700</price>
            </dish>
            <dish>
                <name>Dish8</name>
                <price currency="dol.">800</price>
            </dish>
            <dish>
                <name>Dish9</name>
                <price currency="dol.">900</price>
            </dish>
        </menu>
    </restaurant>
</restaurants>

Вот код моего анализатора:

package com.sitairis.lab2;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class SaxParser {
    private static List<Restaurant> restaurants = new ArrayList<>();

    public static void main(String[] args) {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            XMLHandler handler = new XMLHandler();
            parser.parse(new File("restaurant.xml"), handler);

            for (Restaurant restaurant : restaurants) {
                System.out.println(restaurant.getStreet() + " " + restaurant.getTitle() + " " + restaurant.getCapacity() + " " + restaurant.getCuisine());
                for (Dish dish: restaurant.getDishes()){
                    System.out.println(dish.getTitle());
                }
            }
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }
    }

    private static class XMLHandler extends DefaultHandler {
        private String street, title, cuisine, hall, name, lastElementName;

        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
        }

        @Override
        public void endDocument() throws SAXException {
            super.endDocument();
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) {
            lastElementName = qName;
        }

        @Override
        public void endElement(String uri, String localName, String qName) {
            if ((street != null && !street.isEmpty())
                    && (title != null && !title.isEmpty())
                    && (hall != null && !hall.isEmpty())
                    && (cuisine != null && !cuisine.isEmpty())
                    && (name != null && !name.isEmpty())) {
                Restaurant restaurant = new Restaurant();
                restaurant.setStreet(street);
                restaurant.setTitle(title);
                restaurant.setCapacity(Integer.parseInt(hall));
                restaurant.setCuisine(cuisine);

                Dish dish = new Dish();
                dish.setTitle(name);
                restaurant.setDishes(List.of(dish));

                restaurants.add(restaurant);
                street = null;
                title = null;
                cuisine = null;
                hall = null;
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) {
            String information = new String(ch, start, length);
            information = information.replace("\n", "").trim();
            if (!information.isEmpty()) {
                if (lastElementName.equals("street")) {
                    street = information;
                }
                if (lastElementName.equals("title")) {
                    title = information;
                }
                if (lastElementName.equals("cuisine")) {
                    cuisine = information;
                }
                if (lastElementName.equals("hall")) {
                    hall = information;
                }
                if (lastElementName.equals("name")) {
                    name = information;
                }
            }
        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            super.ignorableWhitespace(ch, start, length);
        }
    }

}

Возможно, все в порядке, но я не понимаю, как я могу получитьДанные этой части:

<dish>
    <name>Dish7</name>
    <price currency="dol.">700</price>
</dish>
<dish>
    <name>Dish8</name>
    <price currency="dol.">800</price>
</dish>
<dish>
    <name>Dish9</name>
    <price currency="dol.">900</price>
</dish>

Я могу получить значение только первого объекта, но не 2-го и третьего. Как я понимаю, что-то должно быть изменено в этом методе, но я не понимаю, как обрабатывать закрывающий тег меню. Так ты можешь мне помочь? Заранее спасибо!

1 Ответ

0 голосов
/ 21 октября 2019

Вы можете использовать Декларативное потоковое сопоставление (DSM) библиотека синтаксического анализа потока для простого анализа сложного XML. это проще, чем SAX.

Вы просто определяете отображение для данных, которые вы хотите извлечь из XML

Вот определения определений для вашего XML.

result: 
  type: array
  path: /restaurants/restaurant
  fields:
    street: 
    title: 
    hall:
    menus:
      path: menu/dish
      type: array
      fields:
        name:
        price: long
        currency:
          xml:
            attribute: true

Java-код для анализа XML:

DSM dsm=new DSMBuilder(new File("path/to/mapping.yaml")).setType(DSMBuilder.TYPE.XML).create();
Object result=  dsm.toObject(xmlFileContent);
// json represntation fo result
dsm.getObjectMapper().writerWithDefaultPrettyPrinter().writeValue(System.out, object);

Вот вывод:

[ {
  "street" : "Street1",
  "title" : "Restaurant1",
  "hall" : "10",
  "menus" : [ {
    "name" : "Dish1",
    "price" : 100
  }, {
    "name" : "Dish2",
    "price" : 200
  }, {
    "name" : "Dish3",
    "price" : 300
  } ]
}, {
  "street" : "Street2",
  "title" : "Restaurant2",
  "hall" : "20",
  "menus" : [ {
    "name" : "Dish4",
    "price" : 400
  }, {
    "name" : "Dish5",
    "price" : 500
  }, {
    "name" : "Dish6",
    "price" : 600
  } ]
}, {
  "street" : "Street3",
  "title" : "Restaurant3",
  "hall" : "30",
  "menus" : [ {
    "name" : "Dish7",
    "price" : 700
  }, {
    "name" : "Dish8",
    "price" : 800
  }, {
    "name" : "Dish9",
    "price" : 900
  } ]
} ]

Если вы хотите напрямую десериализовать класс POJO, это возможнос DSM

...