上善若水
          In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
          posts - 146,comments - 147,trackbacks - 0

          使用DOM方式操作XML文件,即是和DOM樹打交道的過程:在構建XML文件時,首先構建一棵DOM樹,然后將該樹狀結構寫成XML文件;在解析XML文件時,首先將源XML文件解析成一棵DOM樹,然后遍歷這棵DOM樹、或從DOM樹中查找需要的信息。

          關于DOM樹中節點類型、不同節點具有的接口、特性、限制等信息可以參考《DOM樹節點解析》,本文只關注如何構建XML文件與解析XML文件。在構建和解析XML文件中,都以w3school中的books.xml文件的內容為例:

          <?xml version="1.0" encoding="UTF-8"?>

          <bookstore>

              <book category="children">

                  <title lang="en">Harry Potter</title>

                  <author>J K. Rowling</author>

                  <year>2005</year>

                  <price>29.99</price>

              </book>

              <book category="cooking">

                  <title lang="en">Everyday Italian</title>

                  <author>Giada De Laurentiis</author>

                  <year>2005</year>

                  <price>30.00</price>

              </book>

              <bookcategory="web"cover="paperback" >

                  <title lang="en">Learning XML</title>

                  <author>Erik T. Ray</author>

                  <year>2003</year>

                  <price>39.95</price>

              </book>

              <book category="web">

                  <title lang="en">XQuery Kick Start</title>

                  <author>James McGovern</author>

                  <author>Per Bothner</author>

                  <author>Kurt Cagle</author>

                  <author>James Linn</author>

                  <author>Vaidyanathan Nagarajan</author>

                  <year>2003</year>

                  <price>49.99</price>

              </book>

          </bookstore>

          我們都知道Java是一門面向對象的語言,因而我們需要盡量以面向對象的思想我編寫代碼,面向對象編程其中一個比較重要的特點就是基于對象編程,因而我們在編寫這個測試代碼時,也盡量的基于對象操作,而不是像過程式的語言,有一點信息做一點操作。

          在這里,對XML文件中定義的book元素,我們使用Book對象與其對應:

          public class Book {

              private String category;

              private String cover;

              private TitleInfo title;

              private List<String> authors;

              private int year;

              private double price;

              ...

              public static class TitleInfo {

                  private String title;

                  private String lang;

                  ...

              }

          }

          根據XML文件定義構建Book實例:

          public class W3CBooksBuilder {

              public static List<Book> buildBooks() {

                  List<Book> books = new ArrayList<Book>();

                  books.add(buildHarrayBook());

                  books.add(builcEverydayItalian());

                  books.add(buildLearningXML());

                  books.add(buildXQueryKickStart());

                  return books;

              }

              public static Book buildHarrayBook() {

                  Book book = new Book();

                  book.setCategory("children");

                  book.setTitle(new TitleInfo("Harry Potter", "en"));

                  book.setAuthors(Arrays.asList("J K. Rowling"));

                  book.setYear(2005);

                  book.setPrice(29.99);

                  return book;

              }

              public static Book builcEverydayItalian() {

                  ...

              }

              public static Book buildLearningXML() {

                  ...

              }

              public static Book buildXQueryKickStart() {

                  ...

              }

          }

          DOM解析XML文件

          DOM使用DocumentBuilder類來解析XML文件,它提供parse方法,將XML文件解析成一棵DOM樹,并返回Document實例:

          public Document parse(InputStream is);

          public Document parse(InputStream is, String systemId);

          public Document parse(String uri);

          public Document parse(File f);

          public abstract Document parse(InputSource is);

          DocumentBuilder類還提供了判斷當前解析器是否存在命名空間解析、驗證等配置,以及提供了設置EntityResolverErrorHandler的接口。這里使用EntityResolverErrorHandler只是重用SAXAPI,并不表示DOM解析的內部實現一定要基于SAX,然而貌似JDK自帶的DOM解析內部使用的引擎就是SAXT_T

          public abstract boolean isNamespaceAware();

          public abstract boolean isValidating();

          public abstract void setEntityResolver(EntityResolver er);

          public abstract void setErrorHandler(ErrorHandler eh);

          DocumentBuilder提供了 構建Document實例的工廠方法,在以編程方式構建DOM樹時,首先需要構建Document實例,繼而使用Document實例構建其余節點類型,而構建Document實例需要通過DocumentBuilder類來實現:

          public abstract Document newDocument();

          最后,DocumentBuilder還提供了一些額外的方法,比如重置DocumentBuilder實例的狀態,以重用該DocumentBuilder;獲取DOMImplementation實例;獲取Schema實例;判斷XInclude處理模式。

          public void reset();

          public abstract DOMImplementation getDOMImplementation();

          public Schema getSchema();

          public boolean isXIncludeAware();

          DocumentBuilder是一個抽象類,要獲取DocumentBuilder實例,需要使用DocumentBuilderFactoryDocumentBuilderFactory提供了多種查找DocumentBuilder實現類的方法;DocumentBuilderFactory本身也是抽象類,它提供了兩個靜態方法來創建DocumentBuilderFactory實例:

          public static DocumentBuilderFactory newInstance();

          public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader);

          不帶參數的newInstance()方法使用以下步驟查找DocumentBuilderFactory的實現類:

          1.       查看系統屬性中是否存在javax.xml.parsers.DocumentBuilderFactorykey的定義,如果存在,則使用該key定義的值作為DocumentBuilderFactory的實現類。

          2.       查找${java.home}/lib/jaxp.properties屬性文件中是否存在javax.xml.parsers.DocumentBuilderFactorykey的定義,若存在,則使用該屬性文件中以該key定義的值作為DocumentBuilderFactory的實現類。

          3.       查找當前ClassPath(包括jar包中)下是否存在META-INF/services//javax.xml.parsers.DocumentBuilderFactory文件的定義(ServiceProvider),若存在,則讀取該文件中的第一行的值作為DocumentBuilderFactory的實現類。

          4.       若以上都沒有找到,則使用默認的DocumentBuilderFactory的實現類:

          com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

          在找到相應的DocumentBuilderFactory實現類后,實例化該實現類,并返回DocumentBuilderFatory實例。這里的查找機制和XMLReaderFactory查找XMLReader實現類以及commons-logging查找LogFactory的機制很像。

          對帶參數的newInstance()方法,直接使用參數中提供的DocumentBuilderFactory實現類以及ClassLoader來創建DocumentBuilderFactory實例。

          最后,在系統屬性中將jaxp.debug設置為true可以打開調試信息。

          在創建DocumentBuilderFactory實例后,如其名所示,它可以用于獲取DocumentBuilder實例,另外,DocumentBuilderFactory還提供了配置解析器的方法:

          public abstract DocumentBuilder newDocumentBuilder();

           

          public void setNamespaceAware(boolean awareness);

          public boolean isNamespaceAware();

           

          public void setValidating(boolean validating);

          public boolean isValidating();

           

          public void setIgnoringElementContentWhitespace(boolean whitespace);

          public boolean isIgnoringElementContentWhitespace();

           

          public void setExpandEntityReferences(boolean expandEntityRef);

          public boolean isExpandEntityReferences();

           

          public void setIgnoringComments(boolean ignoreComments);

          public boolean isIgnoringComments();

           

          public void setCoalescing(boolean coalescing);

          public boolean isCoalescing();

           

          public void setXIncludeAware(final boolean state);

          public boolean isXIncludeAware();

           

          public abstract void setAttribute(String name, Object value);

          public abstract Object getAttribute(String name);

           

          public abstract void setFeature(String name, boolean value);

          public abstract boolean getFeature(String name);

           

          public Schema getSchema();

          public void setSchema(Schema schema);

          在創建出DocumentBuilderFactory,使用該factory創建DocumentBuilder實例后,就可以使用該DocumentBuilder解析XML文件成一個Document實例,而通過該Document實例就可以遍歷、查找DOM樹,從而獲得想要的信息。在下面的例子中,遍歷DOM樹,創建多個Book實例:

          public class W3CBooksDOMReader {

              private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

             

              private String booksXmlFile;

             

              public W3CBooksDOMReader(String booksXmlFile) {

                  this.booksXmlFile = booksXmlFile;

              }

             

              public List<Book> parse() {

                  Document doc = parseXmlFile();

                  Element root = doc.getDocumentElement();

                  NodeList nodes = root.getElementsByTagName("book");

                 

                  List<Book> books = new ArrayList<Book>();

                  for(int i = 0; i < nodes.getLength(); i++) {

                      books.add(parseBookElement((Element)nodes.item(i)));

                  }

                 

                  return books;

              }

             

              private Document parseXmlFile() {

                  File xmlFile = new File(booksXmlFile);

                  if(!xmlFile.exists()) {

                      throw new RuntimeException("Cannot find xml file: " + booksXmlFile);

                  }

                  try {

                      DocumentBuilder builder = factory.newDocumentBuilder();

                      return builder.parse(xmlFile);

                  } catch(Exception ex) {

                      throw new RuntimeException("Failed to create DocumentBuilder instance", ex);

                  }

              }

             

              private Book parseBookElement(Element bookElement) {

                  String category = bookElement.getAttribute("category");

                  String cover = bookElement.getAttribute("cover");

                 

                  NodeList nodes = bookElement.getElementsByTagName("title");

                  String lang = ((Element)nodes.item(0)).getAttribute("lang");

                 // First way to get content of an Element

                  String title = ((Text)((Element)nodes.item(0)).getFirstChild()).getData().trim();

                 

                  List<String> authors = new ArrayList<String>();

                  nodes = bookElement.getElementsByTagName("author");

                  for(int i = 0; i < nodes.getLength(); i++) {

                      // Second way to get content of an Element

                      String author = nodes.item(0).getTextContent().trim();

                      authors.add(author);

                  }

                 

                  nodes = bookElement.getElementsByTagName("year");

                  int year = Integer.parseInt(nodes.item(0).getTextContent().trim());

                 

                  nodes = bookElement.getElementsByTagName("price");

                  double price = Double.parseDouble(nodes.item(0).getTextContent().trim());

                 

                  Book book = new Book();

                  book.setCategory(category);

                  book.setCover(cover);

                  book.setTitle(new TitleInfo(title, lang));

                  book.setAuthors(authors);

                  book.setYear(year);

                  book.setPrice(price);

                  return book;

              }

             

              public String getBooksXmlFile() {

                  return booksXmlFile;

              }

             

              public static void main(String[] args) {

                  W3CBooksDOMReader reader = new W3CBooksDOMReader("resources/xmlfiles/w3c_books.xml");

                  List<Book> books = reader.parse();

                  System.out.println("result:");

                  for(Book book : books) {

                      System.out.println(book);

                  }

              }

          }

          DOM構建XML文件

          將對象實例序列化成XML文件,首先需要構建DOM樹,即要構建Document實例,然后將該Document實例寫入的XML文件中。如上節所述,可以使用DocumentBuilder類來創建Document實例,然后根據對象實例(Book實例)和需要的XML格式構建節點和節點的排布即可,這里不再詳述。

          要將對象序列化成XML文件還要處理的另一個問題是如何將Document實例寫入到指定的XML文件中,在Java中提供了Transformer接口來做這件事情。這屬于XLSTEXtensible Stylesheet Language)的范疇,不過這里不打算對其做詳細介紹,主要關注如何將Document實例輸出成XML文件。

          Transformer提供了transform方法將Document實例寫入指定的流中:

          public abstract void transform(Source xmlSource, Result outputTarget);

          其中Source接口定義了輸入源,它可以是DOMSource,也可以是SAXSource,或者是自定義的其他Source子類,這里主要介紹DOMSourceSource接口定義了systemId屬性,它表示XML源的位置,XML源不是從URL中獲取的源來說,它為null。具體定義如下:

          public interface Source {

              public void setSystemId(String systemId);

              public String getSystemId();

          }

          DOMSource是對Source的一個具體實現,它接收NodesystemId信息:

          public class DOMSource implements Source {

              private Node node;

          private String systemID;

           

              public DOMSource() { }

              public DOMSource(Node n) {

                  setNode(n);

              }

              public DOMSource(Node node, String systemID) {

                  setNode(node);

                  setSystemId(systemID);

              }

              ...

          }

          Result是對輸出目的的抽象,即將輸入源轉換成目的源。同Source接口,Result接口也定義了systemId屬性,表示目的文件位置,如果目的源不是URL,則改值為null

          public interface Result {

              public void setSystemId(String systemId);

              public String getSystemId();

          }

          JDK中提供了多種Result的實現,如DOMResultStreamResult等。這里只介紹StreamResult,表示其輸出目的是流,我們可以提供WriterOutputStream等實例來接收這些輸出:

          public class StreamResult implements Result {

              public StreamResult() {

              }

              public StreamResult(OutputStream outputStream) {

                  setOutputStream(outputStream);

              }

              public StreamResult(Writer writer) {

                  setWriter(writer);

              }

              public StreamResult(String systemId) {

                  this.systemId = systemId;

              }

              public StreamResult(File f) {

                  setSystemId(f.toURI().toASCIIString());

              }

              ...

              private String systemId;

              private OutputStream outputStream;

              private Writer writer;

          }

          除了transform方法,Transformer類還提供了其他的方法用于配置Transformer在轉換時用到的信息(只提供接口定義,不詳述):

          public void reset();

          public abstract void setParameter(String name, Object value);

          public abstract Object getParameter(String name);

          public abstract void clearParameters();

          public abstract void setURIResolver(URIResolver resolver);

          public abstract URIResolver getURIResolver();

          public abstract void setOutputProperties(Properties oformat);

          public abstract Properties getOutputProperties();

          public abstract void setOutputProperty(String name, String value);

          public abstract String getOutputProperty(String name);

          public abstract void setErrorListener(ErrorListener listener);

          public abstract ErrorListener getErrorListener();

          類似DocumentBuilderTransformer通過TransformerFactory創建,而TransformerFactory的創建如同DocumentBuilderFactory的創建以及查找機制,所不同的是TransformerFactory的屬性名為:javax.xml.transform.TransformerFactory其默認實現類為:com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl,而且它也提供了兩個獲取TransformerFactory實例的方法,這里不再詳述:

          public static TransformerFactory newInstance();

          public static TransformerFactory newInstance(String factoryClassName, ClassLoader classLoader);

          TransformerFactory提供了創建TransformerTemplates的方法,同時也提供了在創建這兩個實例時可以設置的一些配置方法:

          public abstract Transformer newTransformer(Source source);

          public abstract Transformer newTransformer();

          public abstract Templates newTemplates(Source source);

          public abstract Source getAssociatedStylesheet(Source source, String media,

                  String title, String charset);

          public abstract void setURIResolver(URIResolver resolver);

          public abstract URIResolver getURIResolver();

          public abstract void setFeature(String name, boolean value);

          public abstract boolean getFeature(String name);

          public abstract void setAttribute(String name, Object value);

          public abstract Object getAttribute(String name);

          public abstract void setErrorListener(ErrorListener listener);

          public abstract ErrorListener getErrorListener();

          最后,提供一個完整的例子,使用本文開始時創建的List<Book>實例序列化成XML文件:

          public class W3CBooksDOMWriter {

              private static DocumentBuilder docBuilder;

              private static Transformer transformer;

             

              static {

                  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

                  try {

                      docBuilder = factory.newDocumentBuilder();

                  } catch(Exception ex) {

                      throw new RuntimeException("Create DocumentBuilder instance failed.", ex);

                  }

                 

                  TransformerFactory transFactory = TransformerFactory.newInstance();

                  try {

                      transformer = transFactory.newTransformer();

                  } catch(Exception ex) {

                      throw new RuntimeException("Create Transformer instance failed.", ex);

                  }

                  transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

                  transformer.setOutputProperty(OutputKeys.INDENT, "yes");

              }

             

              private List<Book> books;

             

              public W3CBooksDOMWriter(List<Book> books) {

                  this.books = books;

              }

             

              public void toXml(Writer writer) throws Exception {

                  Document doc = buildDOMTree();

                  writeToXmlFile(writer, doc);

              }

             

              public Document buildDOMTree() {

                  Document doc = docBuilder.newDocument();

                  Element root = doc.createElement("bookstore");

                  doc.appendChild(root);

                 

                  for(Book book : books) {

                      Element bookElement = buildBookElement(doc, book);

                      root.appendChild(bookElement);

                  }

                 

                  return doc;

              }

             

              public Element buildBookElement(Document doc, Book book) {

                  Element bookElement = doc.createElement("book");

                  bookElement.setAttribute("category", book.getCategory());

                  bookElement.setAttribute("cover", book.getCover());

                 

                  TitleInfo title = book.getTitle();

                  Element titleElement = doc.createElement("title");

                  titleElement.setAttribute("lang", title.getLang());

                  titleElement.setTextContent(title.getTitle());

                  bookElement.appendChild(titleElement);

                 

                  for(String author : book.getAuthors()) {

                      Element authorElement = doc.createElement("author");

                      authorElement.setTextContent(author);

                      bookElement.appendChild(authorElement);

                  }

                 

                  Element yearElement = doc.createElement("year");

                  yearElement.setTextContent(String.valueOf(book.getYear()));

                  bookElement.appendChild(yearElement);

                 

                  Element priceElement = doc.createElement("price");

                  priceElement.setTextContent(String.valueOf(book.getPrice()));

                  bookElement.appendChild(priceElement);

                 

                  return bookElement;

              }

             

              public void writeToXmlFile(Writer writer, Document doc) throws Exception {

                  DOMSource source = new DOMSource(doc);

                  StreamResult result = new StreamResult(writer);

                  transformer.transform(source, result);

              }

             

              public static void main(String[] args) throws Exception {

                  StringWriter writer = new StringWriter();

                  List<Book> books = W3CBooksBuilder.buildBooks();

                 

                  W3CBooksDOMWriter domWriter = new W3CBooksDOMWriter(books);

                  domWriter.toXml(writer);

                 

                  System.out.println(writer.toString());

              }

          }

          posted on 2012-11-25 17:46 DLevin 閱讀(2392) 評論(0)  編輯  收藏 所屬分類: 學習積累
          主站蜘蛛池模板: 石棉县| 道孚县| 揭阳市| 张掖市| 扶绥县| 昌邑市| 广汉市| 扬中市| 彰化市| 萨迦县| 隆子县| 崇明县| 建阳市| 万安县| 邹平县| 纳雍县| 嘉鱼县| 筠连县| 高密市| 扬中市| 丰镇市| 唐山市| 星子县| 朝阳区| 罗甸县| 黄石市| 武清区| 彭州市| 江都市| 广宁县| 永丰县| 怀柔区| 通许县| 延安市| 马边| 内黄县| 涟水县| 双流县| 五指山市| 高清| 长治县|