美文网首页
响应式API设计实战:设计一个sax解析包装器

响应式API设计实战:设计一个sax解析包装器

作者: JohnYuCN | 来源:发表于2021-07-25 17:50 被阅读0次

    1. 本文组合了Lamda和响应式,设计出一个解析xml的自定义组件,目标是练习新型 API的设计

    2. 案例如下:

    (1)book.xml

    <books>
        <book id="b01">
            <name>john</name>
            <price>23.45</price>
        </book>
        <book id="b02">
            <name>tom</name>
            <price>98</price>
        </book>
    </books>
    

    (2) 组件及测试代码:

    package cn.johnyu.sax;
    
    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.DefaultHandler;
    
    import javax.xml.parsers.SAXParser;
    import javax.xml.parsers.SAXParserFactory;
    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Consumer;
    
    class Book {
        private String id;
        private String name;
        private double price;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Book{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    ", price=" + price +
                    '}';
        }
    }
    
    /**
     * 这是设计出的核心API,使用了"Lamda+响应式api"
     */
    class MyXmlBooksHandler extends DefaultHandler {
        private List<Book> books = null;
        private Book book = null;
        private String info;
        private Consumer<List<Book>> bookListConsumer;
        private Consumer<Book> bookConsumer;
    
        /**
         *
         * @param bookConsumer :每本图书的回调接口
         * @param bookListConsumer: 所有图书的回调接口
         */
        public MyXmlBooksHandler(Consumer<Book> bookConsumer, Consumer<List<Book>> bookListConsumer) {
            this.bookListConsumer = bookListConsumer;
            this.bookConsumer = bookConsumer;
        }
    
        /**
         * 遇到文档开始,实例化图书,并设置id
         */
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if ("books".equals(qName)) {
                books = new ArrayList<>();
            }
            if ("book".equals(qName)) {
                book = new Book();
                String id = attributes.getValue("id");
                book.setId(id);
            }
        }
    
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            String info = new String(ch, start, length).trim();
            this.info = info.isEmpty() ? "" : info;
        }
        /**
         * 遇到文档结束:
         * (1)根据qname,使用info设置图书的各个属性
         * (2)如果遇到的book的结尾,则根据情况要么"消费book"或者"加入到集合中"
         */
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if ("name".equals((qName))) {
                book.setName(info);
            }
            if ("price".equals(qName)) {
                try {
                    double price = Double.parseDouble(info);
                    book.setPrice(price);
                } catch (NumberFormatException e) {
                    throw new SAXException("价格数据解析失败");
                }
            }
    
            if ("book".equals(qName)) {
                //每本书进行一次消费
                if (this.bookConsumer != null) {
                    bookConsumer.accept(book);
                }
                if (this.bookListConsumer != null) {
                    books.add(book);
                }
            }
        }
        //全部文档结尾的事件中,处理"全部图书的消费"
        @Override
        public void endDocument() throws SAXException {
            if (bookListConsumer != null) {
                bookListConsumer.accept(books);
            }
        }
    }
    
    public class MyApp {
    
        public static void main(String[] args) throws Exception {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            File file = new File("books.xml");
    
            //针对每本书进行消费
            MyXmlBooksHandler handler = new MyXmlBooksHandler(System.out::println, null);
            parser.parse(file, handler);
    
    
            //针对所有的书进行消费
            MyXmlBooksHandler handler1 = new MyXmlBooksHandler(null, System.out::println);
            parser.parse(file, handler1);
        }
    }
    
    

    相关文章

      网友评论

          本文标题:响应式API设计实战:设计一个sax解析包装器

          本文链接:https://www.haomeiwen.com/subject/shrimltx.html