如何使用lambda循环XMLStreamReader

时间:2017-10-18 08:37:21

标签: lambda java-8

这更像是一个学习目的而不是真正需要的问题。 我使用下面的代码来检查xml文件是否有效。我不担心这里的模式验证。 我知道XMLStreamReader是一个接口,但我试图找到一些允许我做一些接近的实现:

        Stream<String> s = reader.getText();
        s.forEach(System.out::println);

//我没有lambda的完整代码

public interface CheckXml {

default boolean readFile(String f) throws IOException {
    Boolean result = false;
    FileInputStream inputStream = null;

    try {
        XMLInputFactory factory = XMLInputFactory.newInstance();

        inputStream = new FileInputStream(f);
        XMLStreamReader reader = factory.createXMLStreamReader(inputStream);

        while (reader.hasNext()) {
            reader.next();
        }

    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            inputStream.close();
        }

    }
    return result;
}

//编辑

import com.iread.CheckXml;

public class CheckXmlFiles implements CheckXml {
}

//...
@Test
public void testXmlValidation() throws IOException {
    CheckXml c = new CheckXmlFiles(); 
    assertTrue("For simplicity it is expected 'true'", c.readFile("C:\\_pocs\\temp\\demo.xml"));
}

1 个答案:

答案 0 :(得分:1)

您可以将XmlStreamReader转换为流然后使用它。例如,它需要您创建一个调用hasNextnext方法的迭代器。

在实现的过程中有一些令人头疼的问题:XmlStreamReader会抛出已检查的异常,这会强制您创建一些额外的异常处理代码,这些代码会使代码膨胀。

另请注意,必须在迭代器内关闭XmlStreamReader底层的流。如果您在外面关闭它,您将面临一些流关闭的异常。在这种情况下,您无法使用try with resources

我尝试创建一个简单的流和一个简单的测试,用于计算XML文件中可用元素的数量。

以下是一些玩具代码,用于演示您最终如何做到这一点:

public class XMLStreamReaderStream {

    public static Stream<Integer> fromFile(File f) throws IOException, XMLStreamException {
        XMLInputFactory factory = XMLInputFactory.newInstance();
        Reader inputStream;
        inputStream = new InputStreamReader(new FileInputStream(f), "UTF-8");
        XMLStreamReader reader = factory.createXMLStreamReader(inputStream);

        Iterator<Integer> iterator = new Iterator<>() {
            public Integer next() {
                try {
                    return reader.next();
                } catch (XMLStreamException e) {
                    throw new RuntimeException(e);
                }
            }

            public boolean hasNext() {
                try {
                    boolean hasNext = reader.hasNext();
                    if (!hasNext) {
                        reader.close(); // close the stream here
                    }
                    return hasNext;
                } catch (XMLStreamException e) {
                    return false;
                }
            }

            public void forEachRemaining(Consumer<? super Integer> action) {
                while (hasNext()) {
                    action.accept(next());
                }
            }
        };

        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false);
    }

    public static void main(String[] args) throws IOException, XMLStreamException {
        File sampleXml = new File("stackoverflow1.xml");
        LinkedHashMap<Integer, Long> xmlStats = fromFile(sampleXml).collect(Collectors.groupingBy(Function.identity(),
                LinkedHashMap::new, Collectors.counting()));
        Map<String, Long> readableMap = xmlStats.entrySet().stream().collect(Collectors.toMap(e -> {
            Optional<Field> opt = Stream.of(XMLStreamConstants.class.getDeclaredFields()).filter(f -> {
                try {
                    return e.getKey().equals(f.get(null));
                } catch (IllegalAccessException e1) {
                    return false;
                }
            }).findFirst();
            return opt.map(s -> s.toString().replaceAll(".+\\.", "")).orElseGet(() -> Integer.toString(e.getKey()));
        }, Map.Entry::getValue));
        System.out.println(readableMap);
    }
}

此代码将计算XML文件中找到的标记类型,并将其打印到控制台:

{START_ELEMENT=22, END_DOCUMENT=1, END_ELEMENT=22, CHARACTERS=27}