亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java基于正則表達(dá)式實(shí)現(xiàn)xml文件的解析功能詳解

 更新時(shí)間:2017年08月24日 12:00:46   作者:冷豪  
這篇文章主要介紹了Java基于正則表達(dá)式實(shí)現(xiàn)xml文件的解析功能,結(jié)合實(shí)例形式分析了java使用正則表達(dá)式針對(duì)xml文件節(jié)點(diǎn)的相關(guān)操作技巧,需要的朋友可以參考下

本文實(shí)例講述了Java基于正則表達(dá)式實(shí)現(xiàn)xml文件的解析功能。分享給大家供大家參考,具體如下:

這是我通過(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)。

Node.java:

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();
    }
  }
}

二、創(chuàng)建接口

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

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

XmlFilter.java:

/*
 * 過(guò)濾器的作用是刪除xml文件中不重要的部分。
 * 通常都是一些注釋性文字,不需要被機(jī)器解析。
 */
public interface XmlFilter {
  String filter();
  // 提供自定義正則表達(dá)式,識(shí)別符合過(guò)濾條件的字符串
  String filter(String[] regex);
}

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

XmlParser.java:

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);
}

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

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

SimpleXmlFilter.java:

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;
  }
}

主要是通過(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)。

SimpleXmlParser.java:

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;
  }
}

四、編寫NodeBuilder類

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

NodeBuilder.java:

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);
      }
    }
  }
}

五、測(cè)試

編寫xml測(cè)試文件

測(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è)試類

Demo.java:

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);
  }
}

輸出:

<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>

PS:這里再為大家提供2款非常方便的正則表達(dá)式工具供大家參考使用:

JavaScript正則表達(dá)式在線測(cè)試工具:
http://tools.jb51.net/regex/javascript

正則表達(dá)式在線生成工具:
http://tools.jb51.net/regex/create_reg

更多關(guān)于java算法相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java正則表達(dá)式技巧大全》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總

希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • Java?IO及BufferedReader.readline()出現(xiàn)的Bug

    Java?IO及BufferedReader.readline()出現(xiàn)的Bug

    這篇文章主要介紹了Java?IO及BufferedReader.readline()出現(xiàn)的Bug,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Springboot實(shí)現(xiàn)Java郵件任務(wù)過(guò)程解析

    Springboot實(shí)現(xiàn)Java郵件任務(wù)過(guò)程解析

    這篇文章主要介紹了Springboot實(shí)現(xiàn)Java郵件任務(wù)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Java使用Statement接口執(zhí)行SQL語(yǔ)句操作實(shí)例分析

    Java使用Statement接口執(zhí)行SQL語(yǔ)句操作實(shí)例分析

    這篇文章主要介紹了Java使用Statement接口執(zhí)行SQL語(yǔ)句操作,結(jié)合實(shí)例形式詳細(xì)分析了Java使用Statement接口針對(duì)mysql數(shù)據(jù)庫(kù)進(jìn)行連接與執(zhí)行SQL語(yǔ)句增刪改查等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-07-07
  • Spring的@Conditional詳解

    Spring的@Conditional詳解

    這篇文章主要介紹了Spring的@Conditional詳解,給想要注入Bean增加限制條件,只有滿足限制條件才會(huì)被構(gòu)造并注入到Spring的IOC容器中,通常和@Bean注解一起使用,需要的朋友可以參考下
    2024-01-01
  • Java內(nèi)省實(shí)例解析

    Java內(nèi)省實(shí)例解析

    這篇文章主要介紹了Java內(nèi)省實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • java7鉆石語(yǔ)法知識(shí)點(diǎn)總結(jié)

    java7鉆石語(yǔ)法知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是關(guān)于java7鉆石語(yǔ)法的相關(guān)知識(shí)點(diǎn)內(nèi)容,有需要的朋友們參考下。
    2019-11-11
  • javaweb上傳下載實(shí)例完整版解析(下)

    javaweb上傳下載實(shí)例完整版解析(下)

    這篇文章主要為大家詳細(xì)解析了javaweb上傳下載實(shí)例,本文重點(diǎn)在于文件下載功能的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 通過(guò)實(shí)例解析傳統(tǒng)jar包引用方式

    通過(guò)實(shí)例解析傳統(tǒng)jar包引用方式

    這篇文章主要介紹了通過(guò)實(shí)例解析傳統(tǒng)jar包引用方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • JVM入門之類加載與字節(jié)碼技術(shù)(類加載與類的加載器)

    JVM入門之類加載與字節(jié)碼技術(shù)(類加載與類的加載器)

    Java字節(jié)碼增強(qiáng)指的是在Java字節(jié)碼生成之后,對(duì)其進(jìn)行修改,增強(qiáng)其功能,這種方式相當(dāng)于對(duì)應(yīng)用程序的二進(jìn)制文件進(jìn)行修改。Java字節(jié)碼增強(qiáng)主要是為了減少冗余代碼,提高性能等
    2021-06-06
  • 使用Idea maven創(chuàng)建Spring項(xiàng)目過(guò)程圖解

    使用Idea maven創(chuàng)建Spring項(xiàng)目過(guò)程圖解

    這篇文章主要介紹了使用Idea maven創(chuàng)建Spring項(xiàng)目過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02

最新評(píng)論