天天看點

利用SAX和XSLT轉換Flat Files為XML格式

簡介

當我們需要轉換XML檔案到其它格式檔案的時候,XSLT (eXtensible Stylesheet Language for Transformations)是一個很好的選擇。但是,有的時候我們需要将一個flat檔案或者非XML資料結構轉換為XML和其他标記性語言,如果我們能使用XSLT來轉換以上的資料結構,那絕對是一件很爽的事情。

問題的答案是可以,我們可以使用SAX來 (Simple API for XML)做這件事情。本文将介紹如何建立一個JAVA類,通過該類轉換JAVA的屬性檔案(*.properties)為XML格式。示例将完全證明這個觀點,并且幫助你學習轉換任何資料結構到XML檔案的技術。

本文分為以下幾個部分:

  • SAX Parser和Handler Review
  • 建立一個自定義的SAX Parser (it's easier than you think)
  • The "Echo" Stylesheet
  • 使用TrAX (Transformation API for XML) 轉換SAX Source

    總結

SAX Parser和Handler Review

如果你之前了解SAX,你應該知道SAX是将XML文檔作為事件流處理的API,你可能寫過handler類來接收這些事件。handler類會在下列這些事件觸發時候得到通知:

  • Start of Document
  • Start of Element
  • Characters
  • End of Element
  • End of Document

handler類會如你所願響應這些事件,最容易的方法是通過繼承DefaultHandler對象實作ContentHandler接口。

使用一個自定義的handler解析一個XML檔案,可能需要以下代碼: 

利用SAX和XSLT轉換Flat Files為XML格式

File f  =   new  File( " test.xml " );

利用SAX和XSLT轉換Flat Files為XML格式

ContentHandler handler  =   new  YourCustomHandler();

利用SAX和XSLT轉換Flat Files為XML格式
利用SAX和XSLT轉換Flat Files為XML格式

SAXParserFactory factory  =  SAXParserFactory.newInstance();

利用SAX和XSLT轉換Flat Files為XML格式

SAXParser parser  =  factory.newSAXParser();

利用SAX和XSLT轉換Flat Files為XML格式

parser.parse(file, handler);

SAXParser将執行YourCustomHandler中的回調函數。

建立一個自定義的SAX Parser

在與非XML資料結構打交道的時候,我們需要建立一個Parser用來對已注冊的handler類進行SAX事件廣播。我們甚至可以不寫一個handler類,如果你習慣于動手寫handler的話,這樣看上去很奇怪。

SAXSource對象,用于表示用于轉換的輸入内容,需要用到一個關聯TrAX API的parser。SAXSource對象建立時候以一個實作XMLReader接口的對象作為參數。這個接口包括幾個方法,大多數在我們的例子中還用不到。

下面我們将建立一個基于XMLReader接口的實作,用于轉換JAVA屬性檔案為一個XML事件流。該例子雖然簡單,但已經足夠證明可以将任意資料結構轉換為XML格式。

用于轉換的屬性檔案如下所示: 

Font-Family=Arial

Font-Size=12pt

Background-Color=White

Foreground-Color=Black

我們看到該檔案資料結構實作上是由若幹個key value pairs組成,現在我們需要讀取該檔案,并轉換為一系列的SAX事件:

public   class  PropertyFileParser  implements  XMLReader

{

private  ContentHandler contentHandler  =   null ;

   public  ContentHandler getContentHandler()

  {

     return  contentHandler;

  }

   public   void  setContentHandler(ContentHandler handler)

  {

    contentHandler  =  handler;

  }

}

PropertyFileParser實作了XMLReader接口,盡管我們不是必須得自己寫一個ContentHandler,但我們必須要為content handlers提供一種機制,用于從parser注冊并接收事件。本節中TrAX 将為我們提供這樣一個content handler。

我們的主要任務是實作parse() 方法,這是XMLReader接口所要求實作的。這裡我們取得InputSource,并通過其載入Properties對象。然後,我們調用我們自定義的parse方法。

public   void  parse(InputSource source)  throws  IOException,

                                             SAXException

{

  InputStream is  =  source.getByteStream();

  Properties p  =   new  Properties();

  p.load(is);

  parse(p);

}

自定義的parse方法首先針對文檔的根元素利用startDocument()和startElement()事件進行廣播。通過疊代器周遊properties組成的enumeration,為每個屬性生成startElement(), characters(), endElement()事件。最後,根節點的endElement() 和endDocument()被調用。

private   void  parse(Properties p)  throws  SAXException

{

  contentHandler.startDocument();

  contentHandler.startElement(namespaceURI,

                               " Properties " ,

                               " Properties " , attribs);

  Enumeration e  =  p.propertyNames();

while  (e.hasMoreElements())

{

  String key  =  (String)e.nextElement();

  String value  =  (String)p.getProperty(key);

    contentHandler.startElement(namespaceURI, key, key, attribs);

    contentHandler.characters(value.toCharArray(),  0 ,

                              value.length());

    contentHandler.endElement(namespaceURI, key, key);

}

  contentHandler.endElement(namespaceURI,  " Properties " ,

                                           " Properties " );

  contentHandler.endDocument();

}

為滿足XMLReader接口的要求,我們通過空方法來實作其他幾個接口方法,對于我們的SAX Parser來說自然是小菜一碟。完整的類請參見:PropertyFileParser.java。

Echo Stylesheet

接下來,我們将使用一個非常簡單的Stylesheet對我們parser所關聯的XML文檔進行輸出。該Stylesheet的檔案名為echo.xsl,起這個名字的原因是我們對輸入文檔所作的轉換很簡單,也就是echo一下。到了這一步剩下的事情就非常簡單了,和對XML檔案的格式化輸出幾乎沒有什麼差別。在這裡stylesheet用一種間接的方式扮演了handler的角色,或者說是parser進行事件廣播的接收者。

利用SAX和XSLT轉換Flat Files為XML格式

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

利用SAX和XSLT轉換Flat Files為XML格式
利用SAX和XSLT轉換Flat Files為XML格式

< xsl:stylesheet  version ="1.0"

利用SAX和XSLT轉換Flat Files為XML格式

                xmlns:xsl ="http://www.w3.org/1999/XSL/Transform"

利用SAX和XSLT轉換Flat Files為XML格式

                xmlns:fo ="http://www.w3.org/1999/XSL/Format" >

利用SAX和XSLT轉換Flat Files為XML格式
利用SAX和XSLT轉換Flat Files為XML格式

   < xsl:output  method ="xml"  indent ="yes" />

利用SAX和XSLT轉換Flat Files為XML格式
利用SAX和XSLT轉換Flat Files為XML格式

   < xsl:template  match ="node()" >

利用SAX和XSLT轉換Flat Files為XML格式

     < xsl:copy >

利用SAX和XSLT轉換Flat Files為XML格式

       < xsl:apply-templates />

利用SAX和XSLT轉換Flat Files為XML格式

     </ xsl:copy >

利用SAX和XSLT轉換Flat Files為XML格式

   </ xsl:template >

利用SAX和XSLT轉換Flat Files為XML格式
利用SAX和XSLT轉換Flat Files為XML格式

</ xsl:stylesheet >

利用SAX和XSLT轉換Flat Files為XML格式

我們的"echo" stylesheet完成了一項"deep copy",這個單一的模版針對所有的文檔節點,它複制上下文節點并且所有的子節點都執行了<xsl:apply-templates/>.。這種類型的模版針對XML文檔進行全局性的修改是很有用的。

以下的代碼并沒有進行效率上的優化,如果有此需要請參考作者的另外一篇文章:Optimizing Stylesheet Execution With The Transformation API for XML。 

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

{

//  construct SAXSource with our custom XMLReader

InputStream props  =  ClassLoader.getSystemResourceAsStream

                    ( " my.properties " );

InputSource inputSource  =   new  InputSource(props);

XMLReader parser  =   new  PropertyFileParser();

SAXSource saxSource  =   new  SAXSource(parser, inputSource);

//  construct a transformer using the echo stylesheet

TransformerFactory factory  =  TransformerFactory.newInstance();

StreamSource xslSource  =   new  StreamSource( " echo.xsl " );

Transformer transformer  =  factory.newTransformer(xslSource);

//  transform the SAXSource to the result

StreamResult result  =   new  StreamResult( " properties.xml " );

transformer.transform(saxSource, result);

}

使用了TrAX API,main()方法完成了如下幾個步驟:

SAXSource被建立,包括兩個參數:PropertyFileParser以及input source(儲存了需要解析的屬性檔案)。

利用"echo" stylesheet建立了transformer對象。

SAXSource被轉換為一個Result對象。

雖然示例中我們為了輸出檔案使用了StreamResult,輸出的結果也可以是DOM或者其他類型的Result對象。以下是轉換後的結果: 

利用SAX和XSLT轉換Flat Files為XML格式

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

利用SAX和XSLT轉換Flat Files為XML格式

< Properties >

利用SAX和XSLT轉換Flat Files為XML格式

   < Background-Color > White </ Background-Color >

利用SAX和XSLT轉換Flat Files為XML格式

   < Font-Family > Arial </ Font-Family >

利用SAX和XSLT轉換Flat Files為XML格式

   < Font-Size > 12pt </ Font-Size >

利用SAX和XSLT轉換Flat Files為XML格式

   < Foreground-Color > Black </ Foreground-Color > >

利用SAX和XSLT轉換Flat Files為XML格式

</ Properties >

總結:

轉換非XML資料結構到XML是一個很普遍的問題。大多數的自定義方法都比較麻煩,步驟較多。我們通過示例證明使用标準的XML APIs來完成這項工作是完全可行的。我們的方法可以減少非必要的步驟,直接從源格式轉化到目标XML格式。通過學習和舉一反三,我們很容易發揮SAX和XSLT的效力,實作任意資料結構到XML格式的轉換。 

示例源碼下載下傳

原文作者:Jeff Ryan

原文出處:Transforming Flat Files To XML With SAX and XSLT