JAXB с XMLStreamReader и StreamFilter не завершает - PullRequest
0 голосов
/ 06 марта 2020

Я пытался использовать XMLStreamReader в сочетании с StreamFilter для частичного чтения из файла XML. Основной метод для этого выглядит следующим образом:

public ScheduleList getScheduleListFromXMLFile(File scheduleListFile, ScheduleTimeRange scheduleTimeRange) {

    ScheduleList scheduleList = null;
    try {
        JAXBContext context = JAXBContext.newInstance(this.getJAXBContextClasses());
        Unmarshaller unMarsh = context.createUnmarshaller();

        InputStream inputStream = new FileInputStream(scheduleListFile);

        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
        XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);

        // --- Check if a system state filter is to be applied ------------
        if (scheduleTimeRange!=null && scheduleTimeRange.isValidTimeRange()==true) {
            // --- Add a filter to the XMLStreamReader -------------------- 
            xmlStreamReader = xmlInputFactory.createFilteredReader(xmlStreamReader, new ScheduleList_XMLStreamFilter(scheduleTimeRange));
        }

        JAXBElement<ScheduleList> jaxbElement = (JAXBElement<ScheduleList>) unMarsh.unmarshal(xmlStreamReader);
        xmlStreamReader.close();
        inputStream.close();

        if (jaxbElement!=null) {
            // --- Check if the loaded object is of the required type -----
            Object loadedObject = jaxbElement.getValue();
            if (loadedObject instanceof ScheduleList) {
                scheduleList = (ScheduleList) loadedObject;
            } else {
                JOptionPane.showMessageDialog(this.getOwnerFrame(), getWarningString(), "Wrong object type", JOptionPane.ERROR_MESSAGE);
            }
        }

    } catch (JAXBException e) {
        if (e.getCause() instanceof InstantiationException) {
            // --- Try to load based on the previous version ---
            scheduleList = EomModelUpdater.getScheduleListFromXMLFile(scheduleListFile);
        } else {
            e.printStackTrace();
        }

    } catch (IOException | XMLStreamException ex) {
        ex.printStackTrace();

    } finally {
        convertToTreeScheduleList(scheduleList);            
    }
    return scheduleList;
}

В случае, если 'scheduleTimeRange' имеет значение null, фильтр не будет применен, и операция демаршалинга будет работать нормально. В случае применения фильтра операция не возвращается из метода / строки

JAXBElement<ScheduleList> jaxbElement = (JAXBElement<ScheduleList>) unMarsh.unmarshal(xmlStreamReader);

, даже примененный фильтр сообщает мне, что конец документа достигнут. Метод accept (XMLStreamReader reader) нашего фильтра, который реализует StreamFilter, выглядит следующим образом:

public boolean accept(XMLStreamReader reader) {

    if (reader.isStartElement()==true) {
        // --- Starting elements --------------------
        if (reader.getLocalName().equals("TechnicalSystemStateList")==true) {
            // --- Set default accept ---------------
            this.acceptSystemState = true;

        } else if (reader.getLocalName().equals("GlobalTime")==true) {
            // --- Check if TSSE can be accepted ---- 
            try {
                String globalTimeText = reader.getElementText();
                Long globalTime = this.parseLong(globalTimeText);
                if (globalTime!=null) {
                    this.acceptSystemState = this.scheduleTimeRange.isWithinTimeRange(globalTime);
                }

            } catch (XMLStreamException xmlStreamEx) {
                xmlStreamEx.printStackTrace();
            }
        }

    } else if (reader.isEndElement()==true) {
        // --- Ending elements ----------------------
        if (reader.getLocalName().equals("TechnicalSystemStateList")) {
            return this.acceptSystemState;
        }
    }


    try {
        if (reader.hasNext()==false) {
            System.out.println("Found end of document");

        }

    } catch (XMLStreamException e) {
        e.printStackTrace();
    }

    return true;
}

Я понятия не имею, что здесь не так, и был бы очень рад получить подсказку. В настоящее время мы работаем с Java 8 (jdk1.8.0_191).

1 Ответ

0 голосов
/ 11 марта 2020

После нескольких часов поиска причины, по которой XMLStreamReader не завершился, я нашел ответ в методе bridge () объекта StAXStreamConnector. Как видно из кода ниже, while l oop завершается только в том случае, если мы находимся в конце элемента и если глубина равна 0. То, что я сделал (и предположил, что правильно) с моим StreamFilter, заключалось в том, чтобы не принимать эти конечные теги, где мои критерии фильтра нашли «что-то вне диапазона». В результате глубина переменной не уменьшилась.

Интересно, почему эта реализация не ищет END_DOCUMENT ...!?

            // --- some further code above ---
            OUTER:
            while(true) {
                // These are all of the events listed in the javadoc for
                // XMLEvent.
                // The spec only really describes 11 of them.
                switch (event) {
                    case XMLStreamConstants.START_ELEMENT :
                        handleStartElement();
                        depth++;
                        break;
                    case XMLStreamConstants.END_ELEMENT :
                        depth--;
                        handleEndElement();
                        if(depth==0)    break OUTER;
                        break;
                    case XMLStreamConstants.CHARACTERS :
                    case XMLStreamConstants.CDATA :
                    case XMLStreamConstants.SPACE :
                        handleCharacters();
                        break;
                    // otherwise simply ignore
                }
                event=staxStreamReader.next();
            }
            // --- some further code below ---

Наконец, я написал свой собственный анализатор / обработчик SAX чтобы иметь возможность фильтровать элементы - что, в свою очередь, увеличило скорость чтения файлов по сравнению с JAXB.

...