【Java】为了处理XML而编写了JavaQuery(未完成的版本)

有一個名為ver0.1的類似於jQuery,用於處理Java中的DOM的工具。

最近的Web API主要使用JSON进行通信(大概)。
但是有时候也需要使用XML进行通信。
而且还有时候需要同时处理这两种格式。

目前正碰到这种情况。
为了能够同时处理XML和json,我决定先将它们转换为DOM格式再处理。
幸运的是,Java8已经包含了用于DOM操作的标准库(位于org.w3c.dom下面)。
但是,这个库的搜索功能不太好用。
希望能像JavaScript一样使用getElementsBy…的方式进行搜索,然后将结果作为NodeList对象接收,再提取Node对象,将其转换为Element类型…
虽然它能够解析XML和json,非常方便…

实现目标

    • JavaでWebAPI作成

 

    • 通信はXML/JSON両方からくるのでDOMで扱いたい

 

    今のところ検索ができればいい

实施

可能您看到就能理解,但 JavaQuery 类只是一种装饰。
只是为了将保存的 jQuery 对象的名称固定为$。

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * jQuery風にDocumentオブジェクトを操作したかった
 * @author deigo
 *
 */
public class JavaQuery {

    private static DocumentBuilder documentBuilder;
    static{
        try {
            documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
    }


// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
// オブジェクト生成関連

    public jQuery $;
    public jQuery $() {
        return create();
    }
    public jQuery $(String s) {

        // セレクタなのかXML文字列なのか
        boolean isSelector = s.indexOf("<") >= 0;

        if (false == isSelector) {
            return $.find(s);// セレクタの場合は要素を返却
        } else {
            return create(s);// XML文字列の場合はパースする
        }
    }
    public jQuery $(Element e) {
        return create(e);
    }
    public jQuery $(Document d){
        return create(d);
    }


    /**
     * ドキュメントから$を生成
     * */
    private static jQuery create(Document d){
        return create(new ArrayList<>(Arrays.asList(d.getDocumentElement())));
    }
    private static jQuery create(List<Element> e){
        return new jQuery(e);
    }
    private static jQuery create(Element e){
        return create(new ArrayList<>(Arrays.asList(e)));
    }
    private static jQuery create() {
        return create(documentBuilder.newDocument());
    }
    private static jQuery create(String s){
        jQuery result = null;

        try {
            result = create(documentBuilder.parse(new ByteArrayInputStream(s.getBytes("UTF-8"))));
        } catch (Exception e) {
            //FIXME 適切な処理を
            e.printStackTrace();
        }

        return result;
    }

// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
// コンストラクタ関連

    /** コンストラクタ */
    public JavaQuery() {
        this.$ = create();
    }
    /** コンストラクタ */
    public JavaQuery(Document d) {
        this.$ = create(d);
    }
    /** コンストラクタ */
    public JavaQuery(Element e) {
        this.$ = create(e);
    }
    /** コンストラクタ */
    public JavaQuery(String s) {
        this.$ = create(s);
    }


// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    /**
     * jQuery風オブジェクト
     * @author deigo
     *
     */
    public static class jQuery {

        /** 呼び出し元のjQueryオブジェクト */
        private jQuery prev;
        /** このjQueryオブジェクトが保持している要素リスト */
        private List<Element> elements;


        /** コンストラクタ */
        private jQuery(List<Element> elements, jQuery prev) {
            this.elements = new ArrayList<>();
            this.elements.addAll(elements);
            this.prev = prev;
        }
        /** コンストラクタ */
        private jQuery(List<Element> elements) {
            this.elements = new ArrayList<>();
            this.elements.addAll(elements);
            this.prev = null;
        }

        /* 検索 */

        /**
         * 最初の要素のDOMツリーを検索<br>
         * FIXME 疑似セレクタ対応検討
         * FIXME find および findcoreは最適化されてない とりあえず動くだけ
         * @param selectorString
         * @return 検索結果の$オブジェクト
         */
        public jQuery find(String selectorString){
            jQuery result = null;

            List<String> selectors = new ArrayList<>();
            Arrays.asList(selectorString.split(",")).forEach(selector -> {selectors.add(selector.trim());});

            List<Element> elements = new ArrayList<>();
            for (String selector : selectors) {

                // w3cのオブジェクトにID等から引き当てる機能がないのでタグ名のみ考慮
                elements.addAll(findCore(this.elements.get(0), selector));
            }

            result = new jQuery(elements, this);

            return result;
        }
        /** findのコア処理 */
        private List<Element> findCore(Element element, String selector){
            List<Element> result = new ArrayList<>();

            String subselector = "";
            {
                Pattern p = Pattern.compile("\\s+");
                Matcher m = p.matcher(selector);
                if (m.find()) {
                    subselector = selector.substring(0, m.start());
                    selector = selector.substring(m.end());
                }
            }

            if (null != subselector && false == subselector.isEmpty()) {
                NodeList nl = element.getElementsByTagName(subselector);
                for (int i=0; i<nl.getLength(); i++) {
                    result.addAll( findCore((Element)nl.item(i), selector) );
                }

            } else {
                NodeList nl = element.getElementsByTagName(selector);
                if (nl.getLength()>0) {
                    for (int i=0; i<nl.getLength(); i++) {
                        result.add((Element)nl.item(i));
                    }
                }
            }

            return result;
        }

        /**
         * 子要素を返却
         * @return 子要素の$オブジェクト
         */
        public jQuery children() {
            jQuery result = null;

            NodeList nl = this.elements.get(0).getChildNodes();

            List<Element> elements = new ArrayList<>();
            for (int i=0; i<nl.getLength(); i++) {
                elements.add((Element)nl.item(i));
            }

            result =  new jQuery(elements, this);

            return result;
        }

        /**
         * 親要素を返却
         * @return 親要素の$オブジェクト
         */
        public jQuery parent() {
            jQuery result = null;

            List<Element> elements = new ArrayList<>();
            elements.add((Element)this.elements.get(0).getParentNode());
            result =  new jQuery(elements, this);

            return result;
        }

        /**
         * 呼び出し元の$オブジェクトにポインタを戻す
         * @return 呼び出し元の$オブジェクト
         */
        public jQuery end() {
            return this.prev;
        }

        /* 制御 */

        /**
         * 繰り返し処理<br>
         * 要素の書き換えはできない
         * @param c
         * @return
         */
        public jQuery each(Consumer<Element> c){

            this.elements.forEach(c);
            return this;
        }

        /* 要素返却 */

        /**
         * 要素リストを返却
         * @return
         */
        public List<Element> get() {
            return this.elements;
        }
        /**
         * i番目の要素を返却
         * @param i
         * @return
         */
        public Element get(int i) {
            return this.elements.get(i);
        }

        /**
         * テキストノードを返却
         * @return テキストノード
         */
        public String text() {

            return this.elements.get(0).getTextContent();
        }

        /**
         * テキストノードを更新 *モックです*
         * @param text
         * @return
         */
        public jQuery text(String text) {

            this.elements.get(0).setTextContent(text);
            return this;
        }

    }
}

我认为这是不可能的,但是由于每个方法都可以使用lambda,所以很容易实现。Lambda很厉害。
如果$具有一个元素列表,那么搜索的目标基本上是第一个元素。
我认为这一点与jQuery类似。

用法

        JavaQuery j = new JavaQuery();

        // 要素を抽出して文字列を取り出す
        String order_no= j.$(document).find("order").find("order_no").text();

        // 複数要素の扱い
        j.$(document).find("items").find("item").each(_this_->{
            System.out.println($(_this_).find("item_code").text());
            System.out.println($(_this_).find("name").text());
        });

这个问题 (This issue/problem)

    • 要素の編集ができるようにしたい。

 

    • jQueryと違って検索対象のDOMがころころ変わるので、要検証。

 

    • find見直し

 

    • 属性を扱えるようにする。

 

    • 擬似セレクタも扱えるようにする。

 

    エラーハンドリング

修改

2016/10/13 在 indexOf 判断时出现错误,已修正。

boolean isSelector = s.indexOf("<") > 0;//x
boolean isSelector = s.indexOf("<") >= 0;//o
广告
将在 10 秒后关闭
bannerAds