Java SAX 解析器 - 解析 XML 文档



Java SAX(Simple API for XML) 解析器是 Java 中用于解析 XML 文档的 API。SAX 解析器是基于事件的解析器,并使用 Handler 类来处理事件。回调方法(例如 startElement()、characters()、endElement() 等)在 Handler 类中实现,以获取元素及其属性的详细信息。当解析器识别到相应的事件时,会调用这些回调方法。

使用 Java SAX 解析器解析 XML

以下是使用 SAX 解析器在 Java 中解析 XML 文档需要遵循的步骤:

  • 步骤 1:实现 Handler 类
  • 步骤 2:创建 SAXParser 对象
  • 步骤 3:读取 XML
  • 步骤 4:为 Handler 类创建对象
  • 步骤 5:解析 XML 文档
  • 步骤 6:检索元素

步骤 1:实现 Handler 类

应用程序必须实现一个 Handler 类来处理 XML 文档内的事件。实现 Handler 类后,必须将其注册到 SAX 解析器。

如前一章所述,DefaultHandler 类实现了 ContentHandler 接口。它具有 startDocument()、endDocument()、startElement()、endElement() 和 characters() 等方法,这些方法有助于我们解析 XML 文档。我们根据需要在这些方法内部编写代码。

class UserHandler extends DefaultHandler {

   public void startDocument() {
      ...
   }

   public void startElement(String uri, String localName, String qName, Attributes attributes) {
      ...
   }

   public void characters(char[] ch, int start, int length) {
      ...
   }

   public void endElement(String uri, String localName, String qName) {
      ...
   }

   public void endDocument() {
      ...
   }
}

步骤 2:创建 SAXParser 对象

SAXParserFactory 类用于创建一个新的工厂实例,该实例又用于创建 SAXParser 对象,如下所示:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();

步骤 3:读取 XML

通过指定正确的文件路径来读取 XML 文件,如下所示:

File xmlFile = new File("input.xml");

除了读取文件,我们还可以创建 XML 内容的 InputStream,如下所示:

StringBuilder xmlBuilder = new StringBuilder(); 
xmlBuilder.append(""<?xml version="1.0"?> <rootElement></rootElement>"");
ByteArrayInputStream inputStream = new ByteArrayInputStream( xmlBuilder.toString().getBytes("UTF-8"));

步骤 4:为 Handler 类创建对象

为第一步中已实现的 UserHandler 类创建一个对象,如下所示:

UserHandler userHandler = new UserHandler();

步骤 5:解析 XML 文档

SAXParser 类具有 parse() 方法,该方法接受两个参数,一个是文件,另一个是 DefaultHandler 对象。此函数使用 DefaultHandler 类中实现的函数将给定文件解析为 XML 文档。

saxParser.parse(xmlFile, userHandler);

SAXParser 类还具有 parse() 函数,该函数将内容作为 InputStream 接收:

saxParser.parse(inputStream, userHandler);

步骤 6:检索元素

在完成上述五个步骤后,我们现在可以轻松检索有关元素的所需信息。我们应该在第一步中 Handler 类的内部方法中编写所需的代码。ContentHandler 接口中提供的所有方法都在前一章中进行了讨论,在本节中,我们将实现这些方法以检索有关元素的基本信息,例如元素名称、文本内容和属性。

检索元素名称

元素名称可以从 ContentHandler 接口的 startElement() 方法中获取。此方法的第三个参数是元素的名称,它是 String 类型。我们可以在我们的 Handler 类中实现此方法并获取元素的名称。

示例

在以下示例中,我们使用 StringBuilder 类以字符串的形式获取 XML 内容,并使用 ByteArrayInputStream 转换为字节。

在 UserHandler 类中,我们实现了 startElement() 方法并打印了元素的名称。由于 XML 内容中只有一个元素,因此它成为文档的根元素。

import java.io.ByteArrayInputStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

//Implementing UserHandler Class
class UserHandler extends DefaultHandler{
   public void startElement(String uri, String localName, String qName, Attributes attributes)
	  throws SAXException {
	  System.out.println("Root element is "+qName);
   }
}

public class RetrieveElementName {
   public static void main(String args[]) {
      try {
    	  
    	 //Creating a SAXParser Object             	  
    	 SAXParserFactory factory = SAXParserFactory.newInstance();
         SAXParser saxParser = factory.newSAXParser();
      
         //Reading the XML
         StringBuilder xmlBuilder = new StringBuilder();
   	     xmlBuilder.append("<college>XYZ College</college>");
   	     ByteArrayInputStream input = new ByteArrayInputStream(xmlBuilder.toString().getBytes("UTF-8"));
   	     
   	     //Creating UserHandler object
   	     UserHandler userhandler = new UserHandler();
   	     
   	     //Parsing the XML Document
   	     saxParser.parse(input, userhandler);
   	     
      }  catch (Exception e) {
    	 e.printStackTrace();
      }
   }
} 

根元素名称“college”打印在输出屏幕上。

Root element is college

检索文本内容

要检索元素的文本内容,我们在 ContentHandler 接口中使用 characters() 方法。此方法中包含字符数组、起始位置和长度参数。一旦解析器看到“>”符号后的内容,就会调用此方法。start 参数承载“>”符号后第一个字符的索引,length 包含在遇到“<”符号之前的字符数。

示例

以下 college.xml 文件具有一个子元素“department”,其文本内容为“Computer Science”。让我们编写一个 Java 程序,使用 SAX API 检索此文本内容以及元素名称。

<college>
   <department>Computer Science</department>
</college>

UserHandler 类继承 DefaultHandler,并且我们实现了 startElement()、endElement() 和 characters() 方法。当解析器看到 department 元素内的文本内容时,会调用此方法,我们将其打印到控制台上。

import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

//Implementing UserHandler Class
class UserHandler extends DefaultHandler {
   public void startElement( String uri, String localName, String qName, Attributes attributes)
      throws SAXException { 
      System.out.println("Start Element : " + qName);
   }
	
   public void endElement(String uri, String localName, String qName) {
      System.out.println("End Element : " + qName);
   }
   public void characters(char[] ch, int start, int length) throws SAXException{
      System.out.println("Text Content : " + new String(ch, start, length));
   }	
}
public class RetrieveTextContent {
	public static void main(String args[]) {
	   try {
	
          //Creating a SAXParser Object             	  
          SAXParserFactory factory = SAXParserFactory.newInstance();
          SAXParser saxParser = factory.newSAXParser();
       
          //Reading the XML
          File xmlFile = new File("college.xml");
          
          //Creating UserHandler object
          UserHandler userHandler = new UserHandler();
          
          //Parsing the XML Document
          saxParser.parse(xmlFile, userHandler);
     
	   } catch(Exception e) {
          e.printStackTrace();
	   }
	}
}

显示了 department 元素的文本内容。由于“college”元素内部没有文本内容,因此它为空白。

Start Element : college
Text Content : 
	
Start Element : department
Text Content : Computer Science
End Element : department
Text Content : 

End Element : college

检索属性

startElement() 方法以 Attributes 作为最后一个参数,它包含当前元素内部的属性列表。Attributes 接口内的 getValue("attr_name") 函数用于获取指定属性的值。

示例

我们在“college.xml”文件中添加了一些 department 元素,并且还为每个 department 添加了一个属性“deptcode”。让我们编写一个 Java 程序来检索所有元素及其属性。

<?xml version = "1.0"?>
<college>
   <department deptcode = "DEP_CS23">
      <name>Computer Science</name>
      <staffCount>20</staffCount>
   </department> 
   <department deptcode = "DEP_EC34">
      <name>Electrical and Electronics</name>
      <staffCount>23</staffCount>
   </department> 
   <department deptcode = "DEP_MC89">
      <name>Mechanical</name>
      <staffCount>15</staffCount>
   </department>
</college>

以下 Java 程序在 UserHandler 类中实现了 startElement() 和 characters() 方法。我们初始化了两个布尔变量,以让我们在 department 元素中了解 deptcode 和 staffCount 属性,以便我们可以在 characters() 方法中使用它们来打印属性。

import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

//Implementing UserHandler Class
class UserHandler extends DefaultHandler{
	
   boolean hasDeptName=false;
   boolean hasStaffCount=false;
	
   public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{
		
      if(qName.equals("college")) {
         System.out.println("Root Element : "+qName + "\n");
      }
      if(qName.equals("department")) {
         System.out.println("Current Element : "+qName);
		 System.out.println("Department code : "+ attributes.getValue("deptcode"));
	  }
	  if(qName.equals("name")) {
         hasDeptName=true;
      }
	  if(qName.equals("staffCount")) {
		 hasStaffCount=true;
	  }
   }
	
   public void characters(char[] ch, int start, int length) throws SAXException{
		
      if(hasDeptName) {
         System.out.println("Department Name : "+ new String(ch, start, length));
		 hasDeptName=false;
      }
	  if(hasStaffCount) {
         System.out.println("Staff Count : "+ new String(ch, start, length) + "\n");
         hasStaffCount=false;
      }
   }
}

public class ParseAttributesSAX {
   public static void main(String args[]) {
      try {
                  			
	     //Creating a DocumentBuilder Object             	  
	     SAXParserFactory factory = SAXParserFactory.newInstance();
	     SAXParser saxParser = factory.newSAXParser();
	       
	     //Reading the XML
	     File xmlFile = new File("college.xml");
	     
	     //Creating UserHandler object
	     UserHandler userHandler = new UserHandler();
	     
	     //Parsing the XML Document
	     saxParser.parse(xmlFile, userHandler);
	     
	  } catch(Exception e) {
	          e.printStackTrace();
      }
   }
}

输出窗口显示每个元素的名称以及属性。

Root Element : college

Current Element : department
Department code : DEP_CS23
Department Name : Computer Science
Staff Count : 20

Current Element : department
Department code : DEP_EC34
Department Name : Electrical and Electronics
Staff Count : 23

Current Element : department
Department code : DEP_MC89
Department Name : Mechanical
Staff Count : 15
广告