1

我们必须从为一堆气象站创建假天气数据的生成器中解析 xml 信息。目前我们只是打印它,但我们稍后将不得不对其进行处理。但是,我们收到的数据由多个 XML“文件”组成。有没有办法分离数据并将其拆分为新的<?xml...?>?(数据是一个随机分裂的连续流)我们的代码:

public class Main {

static private final int portNumber = Null;

public static void main(String[] args) {
    try {
        ServerSocket serverSocket = new ServerSocket(portNumber);
        Socket clientSocket = serverSocket.accept();

        BufferedReader clientReader = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));


        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader = factory.createXMLStreamReader(clientReader);

        while (reader.hasNext()) {
            int event = reader.next();

            if (event == XMLStreamConstants.START_ELEMENT) {
                try {
                    String text = reader.getElementText();
                    System.out.println("Element Local Name:" + reader.getLocalName());
                    System.out.println("Text:" + text);

                } catch (XMLStreamException e) {
                    System.out.println(e);
                }
            }
            else if(event == XMLStreamConstants.END_ELEMENT){
                reader.close();
            }

        }
    } catch (IOException e) {
        System.out.println("Error: Unable to Start Server Socket\n\t" + e);
    } catch (XMLStreamException e){
        System.out.println(e);

    }
}
}

xml 的示例(我们一个接一个地收到多个):

<?xml version="1.0"?>
<!-- The WEATHERDATA-element contains multiple MEASUREMENT-elements -->
<WEATHERDATA>
    <MEASUREMENT>
        <STN>123456</STN>

        <DATE>2009-09-13</DATE>

        <TIME>15:59:46</TIME>

        <TEMP>-60.1</TEMP>

        <DEWP>-58.1</DEWP>

        <STP>1034.5</STP>

        <SLP>1007.6</SLP>

        <VISIB>123.7</VISIB>

        <WDSP>10.8</WDSP>

        <PRCP>11.28</PRCP>

        <SNDP>11.1</SNDP>

        <FRSHTT>010101</FRSHTT>

        <CLDC>87.4</CLDC>

        <WNDDIR>342</WNDDIR>
    </MEASUREMENT>
</WEATHERDATA>

我们也有一个 dtd 文件,但我不确定这是否有帮助。

4

1 回答 1

0

使用java.util.Scanner可以作为一种快速的解决方法。该disassemble()函数跳过 XML 声明(如果存在),并将直到并包括下一个结束</WEATHERDATA>标记的所有字符组合成一个“字符串”。然后将结果传递给回调,在此示例中,回调将 XML 转换为带有 JAXB 的 POJO。

我不喜欢Scanner的是它在内部缓冲输入流,因此当流关闭时可能会丢失最后一条消息。

public class DisassembleXml {
    private static final int port = 8888;
    private static final Pattern XML_DECL_PATTERN = Pattern.compile("<\\?xml.*?\\?>");
    private static final Pattern DATA_PATTERN = 
        Pattern.compile(".*?</WEATHERDATA>\\s+", Pattern.DOTALL);

    public static void main(String[] args) throws Exception {
        final ServerSocket serverSocket = new ServerSocket(port);
        System.out.printf("Listening on %d%n", serverSocket.getLocalPort());
        final Socket clientSocket = serverSocket.accept();
        System.out.printf("Processing from %s%n", clientSocket);

        try (Reader sr = new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.ISO_8859_1))
        {
            disassemble(sr, new ConvertToPojoAndPrint());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private static void disassemble(Reader reader, Consumer<String> xmlConsumer) {
        final Scanner sc = new Scanner(reader).useDelimiter("\\Z");
        try {
            while (true) {
                final String xml = sc
                    .skip(XML_DECL_PATTERN)
                    .findWithinHorizon(DATA_PATTERN, 0);
                if (xml == null || xml.isEmpty())
                    break;
                xmlConsumer.accept(xml);
            }
        }
        catch (Exception e) {
            throw new IllegalStateException("cannot interpret stream", e);
        }
    }

    private static class ConvertToPojoAndPrint implements Consumer<String>
    {
        final JAXBContext jaxbContext;
        final Unmarshaller unmarshaller;

        ConvertToPojoAndPrint() throws JAXBException {
            jaxbContext = JAXBContext.newInstance(WeatherData.class);
            unmarshaller = jaxbContext.createUnmarshaller();
        }

        @Override
        public void accept(String xml) {
            try {
                final WeatherData weatherData = (WeatherData) unmarshaller.unmarshal(new StringReader(xml));
                System.out.println("Another sample: " + weatherData);
            }
            catch (Exception e) {
                throw new IllegalStateException(e);
            }
        }
    }

    @XmlRootElement(name = "WEATHERDATA")
    private static class WeatherData
    {
        @XmlElement(name = "MEASUREMENT")
        Measurement measurement;
        @Override
        public String toString() { return "WeatherData{" + "measurement=" + measurement + '}'; }
    }

    private static class Measurement
    {
        @XmlElement(name = "STN")
        String stn;
        // ... skipping the rest of elements for brevity
        @Override
        public String toString() { return "Measurement{" + "stn='" + stn + '\'' + '}'; }
    }
}
于 2018-01-25T14:37:47.140 回答