【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