国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

通過(guò)正則表達(dá)式實(shí)現(xiàn)簡(jiǎn)單xml文件解析

Original 2016-11-11 17:09:09 747
abstract:這是我通過(guò)正則表達(dá)式實(shí)現(xiàn)的xml文件解析工具,有些XHTML文件中包含特殊符號(hào),暫時(shí)還無(wú)法正常使用。設(shè)計(jì)思路:常見(jiàn)的xml文件都是單根樹(shù)結(jié)構(gòu),工具的目的是通過(guò)遞歸的方式將整個(gè)文檔樹(shù)裝載進(jìn)一個(gè)Node對(duì)象。xml文檔樹(shù)上的每一個(gè)節(jié)點(diǎn)都能看做一個(gè)Node對(duì)象,它擁有title、attribute和text三個(gè)自身變量以及一個(gè)childrenNode集合用來(lái)存放子節(jié)點(diǎn),使用正則表達(dá)式完整裝載。一、編寫N

這是我通過(guò)正則表達(dá)式實(shí)現(xiàn)的xml文件解析工具,有些XHTML文件中包含特殊符號(hào),暫時(shí)還無(wú)法正常使用。

設(shè)計(jì)思路:常見(jiàn)的xml文件都是單根樹(shù)結(jié)構(gòu),工具的目的是通過(guò)遞歸的方式將整個(gè)文檔樹(shù)裝載進(jìn)一個(gè)Node對(duì)象。xml文檔樹(shù)上的每一個(gè)節(jié)點(diǎn)都能看做一個(gè)Node對(duì)象,它擁有title、attribute和text三個(gè)自身變量以及一個(gè)childrenNode集合用來(lái)存放子節(jié)點(diǎn),使用正則表達(dá)式完整裝載。

一、編寫Node類

Node對(duì)象是文檔解析的基礎(chǔ),最終可以通過(guò)對(duì)象的不同屬性實(shí)現(xiàn)對(duì)文檔信息的訪問(wèn)。

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class Node implements Serializable {
    // 可以對(duì)Node對(duì)象持久化保存
    private static final long serialVersionUID = 1L;
    private int id;
    // 節(jié)點(diǎn)類型
    private String title;
    // 節(jié)點(diǎn)內(nèi)容
    private String text;
    // 節(jié)點(diǎn)屬性集合
    private Map<String, String> attributes = new HashMap<String, String>();
    // 子節(jié)點(diǎn)集合
    private List<Node> childNodes = new LinkedList<Node>();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Map<String, String> getAttribute() {
        return attributes;
    }

    public void setAttribute(Map<String, String> attribute) {
        this.attributes = attribute;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public List<Node> getChildNode() {
        return childNodes;
    }

    public void setChildNode(List<Node> childNode) {
        this.childNodes = childNode;
    }

    // 將屬性集合轉(zhuǎn)換成一條完整的字符串
    private String attrToString() {
        if (attributes.isEmpty()) {
            return "";
        }
        Iterator<Entry<String, String>> its = attributes.entrySet().iterator();
        StringBuffer buff = new StringBuffer();
        while (its.hasNext()) {
            Entry<String, String> entry = its.next();
            buff.append(entry.getKey() + "=\"" + entry.getValue() + "\" ");
        }
        return " " + buff.toString().trim();
    }

    // 輸出完整的節(jié)點(diǎn)字符串也用到了遞歸
    @Override
    public String toString() {
        String attr = attrToString();
        if (childNodes.isEmpty() && text == null) {
            return "<" + title + attr + "/>\n";
        } else if (childNodes.isEmpty() && text != null) {
            return "<" + title + attr + ">\n" + text + "\n" + "</" + title + ">\n";
        } else {
            StringBuffer buff = new StringBuffer();
            buff.append("<" + title + attr + ">\n");
            if (!text.isEmpty()) {
                buff.append(text + "\n");
            }
            for (Node n : childNodes) {
                buff.append(n.toString());
            }
            buff.append("</" + title + ">\n");
            return buff.toString();
        }
    }
}

Node.java

二、創(chuàng)建接口

把文檔的讀取和分析抽象成接口方便今后替換實(shí)現(xiàn)。

過(guò)濾器:讀取文檔的字符流并刪除注釋的部分。這些信息通常是提供給人閱讀的,程序分析直接忽略。

/*
 * 過(guò)濾器的作用是刪除xml文件中不重要的部分。
 * 通常都是一些注釋性文字,不需要被機(jī)器解析。
 */
public interface XmlFilter {
    String filter();

    // 提供自定義正則表達(dá)式,識(shí)別符合過(guò)濾條件的字符串
    String filter(String[] regex);
}

XmlFilter.java

解析器:將一個(gè)父節(jié)點(diǎn)解析成多條子節(jié)點(diǎn)的字符串。如果返回值為null,代表當(dāng)前節(jié)點(diǎn)下不存在可以繼續(xù)解析的對(duì)象。

import java.util.List;
/*
 * 解析器可以對(duì)一段完整的父節(jié)點(diǎn)字符串提供解析服務(wù)。
 * 將一條父節(jié)點(diǎn)的字符串解析成為多條子節(jié)點(diǎn)字符串
 */
public interface XmlParser {
    // 解析一段父節(jié)點(diǎn),返回子節(jié)點(diǎn)字符串
    List<String> parser(String str);
}

XmlParser.java

三、根據(jù)接口編寫實(shí)現(xiàn)類

回車、換行、制表符以及各種注釋部分的內(nèi)容都被刪除,簡(jiǎn)化字符輸出。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class SimpleXmlFilter implements XmlFilter {
    private String text;
    // 常用的過(guò)濾正則表達(dá)式
    public final static String[] REG = { "\t", "<\\?.*?\\?>", "<!.*?>", "<%.*?%>", "\\s{2,}" };

    // 讀取xml文檔返回字符串
    public SimpleXmlFilter(File file) throws IOException {
        BufferedReader in = new BufferedReader(new FileReader(file));
        StringBuffer buff = new StringBuffer();
        String temp = null;
        while ((temp = in.readLine()) != null) {
            buff.append(temp);
        }
        in.close();
        text = buff.toString().trim();
    }

    @Override
    public String filter() {
        return filter(REG);
    }

    @Override
    public String filter(String[] regex) {
        String result = text;
        for (String reg : regex) {
            result = result.replaceAll(reg, "");
        }
        return result;
    }

}

SimpleXmlFilter.java

主要是通過(guò)正則表達(dá)式區(qū)分一個(gè)節(jié)點(diǎn)內(nèi)部的子節(jié)點(diǎn),考慮到節(jié)點(diǎn)的類型我將它們分為自閉合與非自閉合兩種類型。<title attributes .../>這樣的節(jié)點(diǎn)屬于自閉合類型,它們不包含子節(jié)點(diǎn)和text屬性,它們屬于文檔樹(shù)的葉子節(jié)點(diǎn)。<title attributes ...>text ...</title>這樣的節(jié)點(diǎn)屬于非自閉合類型,它們屬于文檔樹(shù)的分支節(jié)點(diǎn)。

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleXmlParser implements XmlParser {

    @Override
    public List<String> parser(String text) {
        List<String> childrenDocs = new ArrayList<String>();
        // 捕獲根節(jié)點(diǎn)中間的文本
        Pattern p = Pattern.compile("<.*?>(.*)</.*?>");
        Matcher m = p.matcher(text);
        if (m.matches()) {
            String inner = m.group(1);
            // 匹配節(jié)點(diǎn)字符串
            p = Pattern.compile("<(.*?)>");
            m = p.matcher(inner);
            while (m.find()) {
                String s1 = m.group(1);
                // 如果節(jié)點(diǎn)以/結(jié)尾,代表此節(jié)點(diǎn)不包含子節(jié)點(diǎn)
                if (s1.endsWith("/")) {
                    childrenDocs.add(m.group());
                    // 如果節(jié)點(diǎn)既不以/開(kāi)頭,也不以/結(jié)尾則表示需要查找對(duì)應(yīng)的閉合節(jié)點(diǎn)
                } else if (!s1.startsWith("/") && !s1.endsWith("/")) {
                    // 計(jì)算起始字符數(shù)
                    int start = m.end() - m.group().length();
                    // 如果捕獲到未閉合節(jié)點(diǎn)則index++,如果捕獲到閉合節(jié)點(diǎn)則index--
                    int index = 1;
                    while (m.find()) {
                        String s2 = m.group(1);
                        if (!s2.startsWith("/") && !s2.endsWith("/")) {
                            index++;
                        } else if (s2.startsWith("/")) {
                            index--;
                        }
                        // 找到符合條件的閉合節(jié)點(diǎn)則循環(huán)終止
                        if (index == 0) {
                            break;
                        }
                    }
                    // 計(jì)算結(jié)束字符數(shù)
                    int end = m.end();
                    // 截取對(duì)應(yīng)字符串
                    childrenDocs.add(inner.substring(start, end));
                }
            }
        }
        return childrenDocs;
    }

}

SimpleXmlParser.java

四、編寫NodeBuilder類

根據(jù)過(guò)濾器和解析器獲取Node節(jié)點(diǎn)各屬性的值。

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

// 生成Node
public class NodeBuilder {
    private Node root = new Node();
    private XmlParser parser;
    private XmlFilter filter;

    // 提供合適的過(guò)濾器和解析器
    public NodeBuilder(XmlParser parser, XmlFilter filter) {
        this.parser = parser;
        this.filter = filter;
    }

    public Node getRoot(String... regex) {
        String str = null;
        if (regex.length == 0) {
            str = filter.filter();
        } else {
            str = filter.filter(regex);
        }
        buildNodeTree(str, root);
        return root;
    }

    // 設(shè)置節(jié)點(diǎn)類型
    private void buildNodeTitle(String str, Node n) {
        Pattern p = Pattern.compile("<.*?>");
        Matcher m = p.matcher(str);
        if (m.find()) {
            String temp = m.group();
            String s = temp.substring(1, temp.length() - 1).split(" ")[0];
            if (s.endsWith("/")) {
                n.setTitle(s.substring(0, s.length() - 1));
            } else {
                n.setTitle(s.split(" ")[0]);
            }
        }
    }

    // 設(shè)置節(jié)點(diǎn)屬性集合
    private void buildNodeAttribute(String str, Node n) {
        Pattern p = Pattern.compile("<.*?>");
        Matcher m = p.matcher(str);
        if (m.find()) {
            String temp = m.group();
            String s = temp.substring(1, temp.length() - 1);
            // 匹配字符串
            p = Pattern.compile("(\\S*)=\"(.*?)\"");
            m = p.matcher(s);
            while (m.find()) {
                String key = m.group(1).trim();
                String value = m.group(2).trim();
                n.getAttribute().put(key, value);
            }
            // 匹配數(shù)字
            p = Pattern.compile("(\\S*)=(-?\\d+(\\.\\d+)?)");
            m = p.matcher(s);
            while (m.find()) {
                String key = m.group(1).trim();
                String value = m.group(2).trim();
                n.getAttribute().put(key, value);
            }
        }
    }

    // 設(shè)置節(jié)點(diǎn)內(nèi)容,節(jié)點(diǎn)的內(nèi)容是刪除了所有子節(jié)點(diǎn)字符串以后剩下的部分
    private void buildNodeText(String str, Node n) {
        Pattern p = Pattern.compile("<.*?>(.*)</.*?>");
        Matcher m = p.matcher(str);
        List<String> childrenDocs = parser.parser(str);
        if (m.find()) {
            String temp = m.group(1);
            for (String s : childrenDocs) {
                temp = temp.replaceAll(s, "");
            }
            n.setText(temp.trim());
        }
    }

    // 通過(guò)遞歸生成完整節(jié)點(diǎn)樹(shù)
    private void buildNodeTree(String str, Node n) {
        buildNodeTitle(str, n);
        buildNodeAttribute(str, n);
        buildNodeText(str, n);
        // 如果存在子節(jié)點(diǎn)則繼續(xù)下面的操作
        if (!parser.parser(str).isEmpty()) {
            // 對(duì)每一個(gè)子節(jié)點(diǎn)都應(yīng)該繼續(xù)調(diào)用直到遞歸結(jié)束
            for (String temp : parser.parser(str)) {
                Node child = new Node();
                buildNodeTitle(temp, child);
                buildNodeAttribute(temp, child);
                buildNodeText(temp, child);
                n.getChildNode().add(child);
                buildNodeTree(temp, child);
            }
        }
    }
}

NodeBuilder.java

五、測(cè)試

編寫xml測(cè)試文件

<package>
    <!-- 這里是注釋1 -->
    package message before!
    <class id="exp1" path="www.sina.com"/>
    <class id="exp2">
        <class id="inner">
            class message inner.
        </class>
    </class>
    package message middle!
    <!-- 這里是注釋2 -->
    <class id="exp3">
        <method id="md" name="setter" order=1>
            <!-- 這里是注釋3 -->
            <!-- 這里是注釋4 -->
            <para ref="String"/>
            <para ref="exp1">
                method message inner!
            </para>
        </method>
    </class>
    package message after!
</package>

測(cè)試文件

編寫測(cè)試類

import java.io.File;
import java.io.IOException;

public class Demo {
    public static void main(String[] args) {
        File f = new File("xxx");
        XmlFilter filter = null;
        try {
            filter = new SimpleXmlFilter(f);
        } catch (IOException e) {
            e.printStackTrace();
        }
        XmlParser parser = new SimpleXmlParser();
        NodeBuilder builder = new NodeBuilder(parser, filter);
        Node node = builder.getRoot();
        System.out.println(node);
    }
}

Demo.java

輸出

<package>
package message before!package message middle!package message after!
<class path="www.sina.com" id="exp1"/>
<class id="exp2">
<class id="inner">
class message inner.
</class>
</class>
<class id="exp3">
<method name="setter" id="md" order="1">
<para ref="String"/>
<para ref="exp1">
method message inner!
</para>
</method>
</class>
</package>

System.out.println...


Release Notes

Popular Entries