做数据分析必须了解的获取数据与清洗数据技巧
每个数据科学家都需要处理存储在磁盘中的数据,这些数据涉及的格式有ASCII文本、PDF、XML、JSON等。此外,数据还可以存储在数据库表格中。在对数据进行分析之前,数据科学家首先要做的是从这些数据源获取各种格式的数据,并对这些数据进行清洗,去除其中的噪声。今天推荐的图书是《Java数据科学指南》一书,并从中节选第一章内容,从本文中我们将学习这些内容,即了解如何从不同数据源获取各种格式的数据。
在这一过程中,我们将用到外部Java库(Java归档文件,简称JAR文件),这些库的使用不仅限于本文,还贯穿于《Java数据科学指南》一书。这些库由不同开发者或组织开发,方便了大家的使用。编写代码时,我们会用到Eclipse IDE工具,它是Windows平台下最好的集成开发环境,全书都会使用它。接下来,我们将讲解如何导入任意一个外部JAR文件,以下各个部分将指导你把外部JAR文件导入到项目中,跟随步骤动手去做即可。
对于一个Eclipse项目,你可以采用如下方法添加JAR文件:首先依次单击“Project|Build Path|Configure Build Path”,在Libraries选项卡中,单击“Add External JARs”,选择你想添加到项目的外部JAR文件,如图1-1所示。
图1-1
这部分内容(以及后面各部分内容)是为那些想从复杂目录结构中提取文件路径与名称的数据科学家准备的,以方便进一步进行后续分析。这里的复杂目录结构是指在一个根目录下包含大量目录与文件。
准备工作
开始之前,需要做如下准备工作。
1.创建复杂的目录结构(目录层数你自己决定)。
2.在其中一些目录中创建文本文件,而在另一些目录中留空。
操作步骤
1.首先编写一个static
方法,即listFiles(File rootDir),它带有一个File
类型的参数,该参数可以是根目录或起始目录。这个方法将返回一系列文件,这些文件存在于参数所指定的根目录(以及其他所有下级子目录)中。
1 public static Set<File> listFiles(File rootDir) {
2.然后,创建一个HashSet
对象,用来包含文件信息。
1 Set<File> fileSet = new HashSet<File>();
3.在创建好HashSet
对象之后,要检查参数指定的根目录及其子目录是否为null
。当为null
时,直接把HashSet对象返回即可,不需要进行进一步处理。
1 if (rootDir == null || rootDir.listFiles() == null){
2 return fileSet;
3 }
4.接着,检查根目录中的每个目录(或文件),判断它是文件还是目录。如果是文件,就把它添加到HashSet
中;如果是一个目录,就递归地调用本方法,并把当前目录路径与名称传递给它。
1 for (File fileOrDir : rootDir.listFiles()) {
2 if (fileOrDir.isFile()){
3 fileSet.add(fileOrDir);
4 }
5 else{
6 fileSet.addAll(listFiles(fileOrDir));
7 }
8 }
5.最后,把HashSet
返回给该方法的调用者。
1 return fileSet;
2 }
listFiles(File rootDir)方法的完整代码如下,包含执行该方法所需要的类与驱动方法。
1import java.io.File;
2import java.util.HashSet;
3import java.util.Set;
4public class TestRecursiveDirectoryTraversal {
5 public static void main(String[] args){
6 System.out.println(listFiles(new File("Path for root
7 directory")).size());
8 }
9 public static Set<File> listFiles(File rootDir) {
10 Set<File> fileSet = new HashSet<File>();
11 if(rootDir == null || rootDir.listFiles()==null){
12 return fileSet;
13 }
14 for (File fileOrDir : rootDir.listFiles()) {
15 if (fileOrDir.isFile()){
16 fileSet.add(fileOrDir);
17 }
18 else{
19 fileSet.addAll(listFiles(fileOrDir));
20 }
21 }
22 return fileSet;
23 }
24}
{:--}
....\警告.tif{8%}请注意,代码中的HashSet
用来存储文件路径与名称。这意味着我们不会有任何重复项,这是因为Java中的Set这种数据结构不包含重复项。
1.3 使用Apache Commons IO从多层目录中提取所有文件名
你可以使用前面一部分演示的操作步骤,采用递归方法把多层目录中的文件名列出来。除此之外,我们还有另外一种更简单、更方便的方法来完成它,那就是使用Apache Commons IO,并且只需编写少量代码即可。
准备工作
开始之前,需要做如下准备。
1.本部分会用到一个名称为Commons IO的Java库,它来自于Apache基金会。全书中,我们会使用Commons IO 2.5版本,请从Commons官网下载JAR文件。
2.在Eclipse中,把下载的JAR文件包含到你的项目中(作为外部JAR文件)。
操作步骤
1.创建listFiles方法,它带有一个参数,用来指定层级目录的根目录。
1 public void listFiles(String rootDir){
2.创建一个文件对象,并把根目录名传递给它。
1 File dir = new File(rootDir);
3.Apache Commons库的FileUtils
类中包含一个名称为listFiles()
方法。使用这个方法提取所有文件名,并且把它们放入一个带有<File>
泛型的列表变量中。使用TrueFileFilter.INSTANCE
来匹配所有目录。
1 List<File> files = (List<File>) FileUtils.listFiles(dir,
2 TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
4.我们可以像下面这样把文件名显示在标准输出中。由于我们把文件名放入了一个列表之中,所以我们可以通过某种方法对这些文件中的数据进行进一步处理。
1 for (File file : files) {
2 System.out.println("file: " + file.getAbsolutePath());
3 }
5.关闭方法。
1 }
完整代码包括方法代码、类代码,以及驱动方法,如下所示:
1import java.io.File;
2import java.util.List;
3import org.apache.commons.io.FileUtils;
4import org.apache.commons.io.filefilter.TrueFileFilter;
5public class FileListing{
6 public static void main (String[] args){
7 FileListing fileListing = new FileListing();
8 fileListing.listFiles("Path for the root directory here");
9 }
10 public void listFiles(String rootDir){
11 File dir = new File(rootDir);
12 List<File> files = (List<File>) FileUtils.listFiles(dir,
13 TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
14 for (File file : files) {
15 System.out.println("file: " + file.getAbsolutePath());
16 }
17 }
如果你想把带有一些特定扩展名的文件列出来,还可以使用Apache Commons库中的listFiles
方法。但是这个方法的参数有些不同,它拥有3个参数,分别为文件目录、扩展名(String[]
)、递归与否。在这个库中还有一个有趣的方法,即listFilesAndDirs(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter),如果你想把文件与目录全部列出来,可以使用它。
1.4使用Java 8从文本文件一次性读取所有内容
在许多场合下,数据科学家所拥有的数据是文本格式的。我们有很多方法可以用来读取文本文件的内容,这些方法各具优缺点:一些方法执行起来耗时、耗内存,而另一些方法执行速度很快,也不需要消耗太多计算机内存;一些方法可以把全部文本内容一次性读出,而另一些方法则只能一行行地读取文本文件。至于到底要选择哪种方法,则取决于你所面对的任务,以及你决定采用何种方法来处理这个任务。
在这部分中,我们将演示使用Java 8把文本文件的全部内容一次性读出来的方法。
操作步骤
1.首先,创建一个String
对象,用来保存待读取的文本文件的目录与名称。
1 String file = "C:/dummy.txt";
2.使用Paths
类的get()
方法,可以得到待读文件的路径。get()
方法的参数是String
对象,用来指定文件名,它的输出作为lines()
方法的输入。lines()
方法包含于Files
类之中,用来读取一个文件的所有行,并且返回Stream
,也就是说,这个方法的输出定向到一个Stream
变量。因为我们的dummy.txt
文件中包含字符串数据,所以把Stream
变量的泛型设置为String
。
整个读取过程需要放入一个try...catch
块中,用来应对读取过程中可能发生的异常,比如当试图读取的文件不存在或已损坏时,就会抛出异常。
下面代码用来把dummy.txt
文件中的内容全部显示出来。在stream
变量中包含着文本文件的所有行,所以需要使用它的forEach()
方法显示出每行内容。
1 try (Stream<String> stream = Files.lines(Paths.get(file))) {
2 stream.forEach(System.out::println); } catch (IOException e) {
3 System.out.println("Error reading " + file.getAbsolutePath());
4 }
1.5使用Apache Commons IO从文本文件一次性读取所有内容
在上一节中我们学习了使用Java8从文本文件中一次性读取所有内容,其实我们也可以使用Apache Commons IO API一次性读取文本文件的所有内容。
准备工作
开始之前,需要做如下准备。
1.本部分,我们会用到一个名为Apache Commons IO的Java库。
2.在Eclipse中,把下载好的JAR文件包含到你的项目中。
操作方法
1.假设你要读取的文件为dummy.txt
,它位于C:/
目录之下。首先,需要创建一个文件对象,用来访问这个文件,如下所示:
1 File file = new File("C:/dummy.txt");
2.接着,创建一个字符串对象,用来保存文件中的文本内容。这里我们要使用readFileToString()
方法,它来自于Apache Commons IO库,是FileUtils
类的一个成员方法。调用这个方法的方式有很多,但是现在,你只需知道我们要传递两个参数给它,第一个参数是file
对象,用来指定要读取的文件,第二个参数是文件的编码,在示例中,我们将其设置为UTF-8
。
1 String text = FileUtils.readFileToString(file, "UTF-8");
3.只要使用上面两行代码,我们就可以读取文本文件内容,并将它们存入一个String变量中。但是,你可不是一个普通的数据科学家,你比其他人要聪明得多。所以,你在上面两行代码的前后又添加了几行代码,用来处理Java方法抛出的异常,比如你试图读取的文件不存在或者已经损坏,就会触发异常。为此,我们需要把上面两行代码放入到一个try...catch
块之中,如下所示:
1 File file = new File("C:/dummy.txt");
2 try {
3 String text = FileUtils.readFileToString(file, "UTF-8");
4 } catch (IOException e) {
5 System.out.println("Error reading " + file.getAbsolutePath());
6 }
1.6 使用Apache Tika提取PDF文本
在解析与提取数据时,最难搞的文件类型之一是PDF文件。有些PDF文件甚至无法解析,因为它们有密码保护,而其他一些则包含着扫描的文本与图像。所以,这种动态文件类型有时会成为数据科学家的梦魇。本部分演示如何使用Apache Tika从PDF文件提取文本,当然前提是PDF文件没有被加密,也没有密码保护,而只包含非扫描的文本。
准备知识
开始之前,需要先做如下准备。
1.下载Apache Tika 1.10 JAR文件,并且将其作为外部Java库包含到你的Eclipse项目中。
2.把任意一个未锁定的PDF文件保存到C:/
目录之下,并且命名为testPDF.pdf
。
操作步骤
1.创建一个名称为convertPdf(String)
的方法,它带有一个字符串参数,用来指定PDF文件名称。
1 public void convertPDF(String fileName){
2.创建一个输入流,用来以字节流的形式包含PDF数据。
1 InputStream stream = null;
3.创建一个try
块,如下所示:
1 try{
4.把文件指派给刚刚创建好的stream
。
1 stream = new FileInputStream(fileName);
5.在Apache Tika包中包含着许多不同的解析器。如果你不知道该选用哪一个,或者说你还有其他类型的文档需要转换,那么你应该使用AutoDetectParser
解析器,如下所示:
1 AutoDetectParser parser = new AutoDetectParser();
6.创建一个handler,用来处理文件的正文内容。请注意,创建时需要把构造函数的参数设为-1
。通常,Apache Tika会对处理的文件进行限制,要求它至多包含100 000个字符。使用-1
让这个handler忽略这个限制。
1 BodyContentHandler handler = new BodyContentHandler(-1);
7.创建一个metadata对象。
1 Metadata metadata = new Metadata();
8.调用解析器对象的parser()
方法,并把上面创建的这些对象传递给它。
1 parser.parse(stream, handler, metadata, new ParseContext());
9.使用handler对象的tostring()
方法,获取从文件中提取的正文文本。
1 System.out.println(handler.toString());
10.关闭try
块,并且添加catch
与finally
块。最后,关闭整个方法,如下所示:
1 }catch (Exception e) {
2 e.printStackTrace();
3 }finally {
4 if (stream != null)
5 try {
6 stream.close();
7 } catch (IOException e) {
8 System.out.println("Error closing stream");
9 }
10 }
11 }
下面代码包含convertPdf(String)方法的完整代码,以及相应的类与驱动方法。在调用convertPdf(String)方法时,你需要提供待转换的PDF文件的路径与名称,即把该方法的参数指定为C:/testPDF.pdf
。
1import java.io.FileInputStream;
2import java.io.IOException;
3import java.io.InputStream;
4import org.apache.tika.metadata.Metadata;
5import org.apache.tika.parser.AutoDetectParser;
6import org.apache.tika.parser.ParseContext;
7import org.apache.tika.sax.BodyContentHandler;
8public class TestTika {
9 public static void main(String args[]) throws Exception {
10 TestTika tika = new TestTika();
11 tika.convertPdf("C:/testPDF.pdf");
12 }
13 public void convertPdf(String fileName){
14 InputStream stream = null;
15 try {
16 stream = new FileInputStream(fileName);
17 AutoDetectParser parser = new AutoDetectParser();
18 BodyContentHandler handler = new BodyContentHandler(-1);
19 Metadata metadata = new Metadata();
20 parser.parse(stream, handler, metadata, new
21 ParseContext());
22 System.out.println(handler.toString());
23 }catch (Exception e) {
24 e.printStackTrace();
25 }finally {
26 if (stream != null)
27 try {
28 stream.close();
29 } catch (IOException e) {
30 System.out.println("Error closing stream");
31 }
32 }
33 }
34}
1.7 使用正则表达式清洗ASCII文本文件
ASCII文本文件中通常会包含一些非必要的字符,这些字符通常产生于转换过程中,比如把PDF转换为文本或把HTML转换为文本的过程中。并且,这些字符常常被看作噪声,它们是数据处理的主要障碍之一。本部分,我们学习使用正则表达式为ASCII文本数据清洗一些噪声的方法。
操作步骤
1.创建一个名为cleanText(String)
的方法,它带有一个String
类型的参数,用来指定要清洗的文本。
1 public String cleanText(String text){
2.在你的方法中,添加如下几行代码,而后把清洗后的文本返回,并关闭方法。在如下代码中,第一行代码用来去掉非ASCII
字符,紧接的一行用来把连续的空格字符替换为单个空格字符。第三行用来清除所有ASCII
控制字符。第四行用来去除ASCII
非打印字符。最后一行用来从Unicode移除非打印字符。
1 text = text.replaceAll("[^p{ASCII}]","");
2 text = text.replaceAll("s+", " ");
3 text = text.replaceAll("p{Cntrl}", "");
4 text = text.replaceAll("[^p{Print}]", "");
5 text = text.replaceAll("p{C}", "");
6 return text;
7 }
以下代码是方法的完整代码,包含相应类与驱动方法。
1public class CleaningData {
2 public static void main(String[] args) throws Exception {
3 CleaningData clean = new CleaningData();
4 String text = "Your text here you have got from some file";
5 String cleanedText = clean.cleanText(text);
6 //清洗文本处理
7 }
8 public String cleanText(String text){
9 text = text.replaceAll("[^p{ASCII}]","");
10 text = text.replaceAll("s+", " ");
11 text = text.replaceAll("p{Cntrl}", "");
12 text = text.replaceAll("[^p{Print}]", "");
13 text = text.replaceAll("p{C}", "");
14 return text;
15 }
16}
1.8 使用Univocity解析CSV文件
对数据科学家来说,另一种经常处理的文件格式是CSV(逗号分隔)文件,在这种文件中数据之间通过逗号进行分隔。CSV文件非常流行,因为大部分电子表格应用程序都可以读取它,比如MS Excel。
本部分,我们将学习解析CSV文件,以及处理所提取的数据点的方法。
准备工作
开始之前,需要先做如下准备。
1.下载Univocity JAR文件,并将其作为外部库添加到你的Eclipse项目中。
2.使用Notepad创建一个CSV文件,它包含如下数据。创建好之后,把文件的扩展名修改为.csv
,并把它保存到C盘之下,即C:/testCSV.csv
。
1 Year,Make,Model,Description,Price
2 1997,Ford,E350,"ac, abs, moon",3000.00
3 1999,Chevy,"Venture ""Extended Edition""","",4900.00
4 1996,Jeep,Grand Cherokee,"MUST SELL!
5 air, moon roof, loaded",4799.00
6 1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
7 ,,"Venture ""Extended Edition""","",4900.00
操作步骤
1.创建一个名为parseCsv(String)
的方法,它带有一个String类型的参数,用来指定待解析的文件名。
1 public void parseCsv(String fileName){
2.而后创建一个配置对象,该对象用来提供多种配置选项。
1 CsvParserSettings parserSettings = new CsvParserSettings();
3.借助于配置对象,你可以打开解析器的自动检测功能,让它自动侦测输入中包含何种行分隔符序列。
1 parserSettings.setLineSeparatorDetectionEnabled(true);
4.创建一个RowListProcessor
对象,用来把每个解析的行存储在列表中。
1RowListProcessor rowProcessor = new RowListProcessor();
5.你可以使用RowProcessor
来配置解析器,以对每个解析行的值进行处理。你可以在com.univocity.parsers.common.processor
包中找到更多RowProcessors
,但是你也可以自己创建。
1 parserSettings.setRowProcessor(rowProcessor);
6.如果待解析的CSV文件包含标题头,你可以把第一个解析行看作文件中每个列的标题。
1 parserSettings.setHeaderExtractionEnabled(true);
7.接下来,使用给定的配置创建一个parser
实例。
1 CsvParser parser = new CsvParser(parserSettings);
8.parser实例的parse()
方法用来解析文件,并把每个经过解析的行指定给前面定义的RowProcessor
。
1 parser.parse(new File(fileName));
9.如果解析中包含标题,则可使用如下代码获取这些标题。
1 String[] headers = rowProcessor.getHeaders();
10.随后,你可以很容易地处理这个字符串数组,以获取这些标题值。
11.另一方面,我们在列表中可以找到行值。只要使用一个for循环即可把列表打印出来,如下所示。
1 List<String[]> rows = rowProcessor.getRows();
2 for (int i = 0; i < rows.size(); i++){
3 System.out.println(Arrays.asList(rows.get(i)));
4 }
12.最后,关闭方法。
1 }
整个方法的完整代码如下所示:
1import java.io.File;
2import java.util.Arrays;
3import java.util.List;
4import com.univocity.parsers.common.processor.RowListProcessor;
5import com.univocity.parsers.csv.CsvParser;
6import com.univocity.parsers.csv.CsvParserSettings;
7public class TestUnivocity {
8 public void parseCSV(String fileName){
9 CsvParserSettings parserSettings = new CsvParserSettings();
10 parserSettings.setLineSeparatorDetectionEnabled(true);
11 RowListProcessor rowProcessor = new RowListProcessor();
12 parserSettings.setRowProcessor(rowProcessor);
13 parserSettings.setHeaderExtractionEnabled(true);
14 CsvParser parser = new CsvParser(parserSettings);
15 parser.parse(new File(fileName));
16 String[] headers = rowProcessor.getHeaders();
17 List<String[]> rows = rowProcessor.getRows();
18 for (int i = 0; i < rows.size(); i++){
19 System.out.println(Arrays.asList(rows.get(i)));
20 }
21 }
22 public static void main(String[] args){
23 TestUnivocity test = new TestUnivocity();
24 test.parseCSV("C:/testCSV.csv");
25 }
26}
有很多采用Java编写的CSV解析器。但是,相比较而言,Univocity是执行速度最快的一个。
1.9 使用Univocity解析TSV文件
不同于CSV文件,TSV(制表符分隔)文件中所包含的数据通过TAB制表符进行分隔。本部分,我们将学习使用Univocity从TSV文件提取数据点的方法。
准备工作
开始之前,先做如下准备工作。
1.下载Univocity JAR文件,并将其作为外部库包含到你的Eclipse项目中。
2.使用Notepad创建一个TSV文件,它包含如下数据。创建好之后,把文件的扩展名修改为.tsv
,并把它保存到C盘之下,即C:/testTSV.tsv
。
1Year Make Model Description Price
21997 Ford E350 ac, abs, moon 3000.00
31999 Chevy Venture "Extended Edition" 4900.00
41996 Jeep Grand Cherokee MUST SELL!nair, moon roof, loaded 4799.00
51999 Chevy Venture "Extended Edition, Very Large" 5000.00
6 Venture "Extended Edition" 4900.00
1.创建一个名称为parseTsv(String)
的方法,它带有一个String类型的参数,用来指定待解析的文件名。
1 public void parseTsv(String fileName){
2.本部分中TSV文件的行分隔符为换行符或n
。为了把字符n设置为行分隔符,修改设置如下所示。
1 settings.getFormat().setLineSeparator("n");
3.使用这些设置,创建一个TSV解析器。
1 TsvParser parser = new TsvParser(settings);
4.使用如下代码,把TSV文件中的所有行一次性解析出来。
1 List<String[]> allRows = parser.parseAll(new File(fileName));
5.遍历列表对象,打印或处理数据行,代码如下所示。
1 for (int i = 0; i < allRows.size(); i++){
2 System.out.println(Arrays.asList(allRows.get(i)));
3 {
6.最后,关闭方法。
1 }
下面代码中包含整个方法的完整代码,以及相应类与驱动方法。
1import java.io.File;
2import java.util.Arrays;
3import java.util.List;
4import com.univocity.parsers.tsv.TsvParser;
5import com.univocity.parsers.tsv.TsvParserSettings;
6public class TestTsv {
7 public void parseTsv(String fileName){
8 TsvParserSettings settings = new TsvParserSettings();
9 settings.getFormat().setLineSeparator("n");
10 TsvParser parser = new TsvParser(settings);
11 List<String[]> allRows = parser.parseAll(new File(fileName));
12 for (int i = 0; i < allRows.size(); i++){
13 System.out.println(Arrays.asList(allRows.get(i)));
14 }
15 }
16}
1.10 使用JDOM解析XML文件
通常,文本数据是没有结构的,不同于文本数据,在XML文件中的数据是具有结构的。XML是组织数据的一种流行方式,借助它,我们可以非常方便地准备、传递以及利用数据。有很多方法可以用来解析XML文件的内容。本书中,我们将学习使用一个名为JDOM的Java库来解析XML文件。
准备工作
开始之前,先做如下准备工作。
1.下载JDOM 2.06版本(JAR文件)。
2.在Eclipse中,创建一个项目,并把上面下载的JAR文件作为外部JAR文件包含进去。
3.打开notepad,新建一个名称为dummyxml
的文件,文件扩展名为.xml
,文件包含的内容简单如下:
1 <?xml version="1.0"?>
2 <book>
3 <author>
4 <firstname>Alice</firstname>
5 <lastname>Peterson</lastname>
6 </author>
7 <author>
8 <firstname>John</firstname>
9 <lastname>Doe</lastname>
10 </author>
11 </book>
操作步骤
1.创建一个名称为builder
的SAXBuilder
对象。
1 SAXBuilder builder = new SAXBuilder();
2.接下来,你需要创建一个File
对象,用来指向待解析的XML文件。如果你已经把XML文件保存到C
盘之下,则将其放入如下代码片段中。
1 File file = new File("c:/dummyxml.xml");
3.在try
语句块中,需要创建一个Document
对象,它表示你的XML文件。
1 try {
2 Document document = (Document) builder.build(file);
4.在解析呈现树状结构的XML文件时,需要知道文件的根元素,以便开始遍历整个树(换言之,开始进行系统的解析)。因此,需要创建一个Element
类型的rootNode
对象,用来保存根元素,在我们的示例中,它对应于<book>
节点。
1 Element rootNode = document.getRootElement();
5.接着,获取根节点下所有名称为author
的子节点。由于调用getChildren()方法所得到的是子节点列表,所以还需要有一个列表变量来存储它们。
1 List list = rootNode.getChildren("author");
6.然后,使用for
循环遍历整个子节点列表,以获取列表中的项目元素。每个元素都存储在Element
类型的node变量中。这个变量有一个名称为getChildText()
的方法,其参数为子元素名称,返回子元素的文本内容,如果指定的子元素不存在,就返回null
。这个方法用起来非常方便,因为调用getChild().getText()
可能会抛出NullPointerException
异常。
1 for (int i = 0; i < list.size(); i++) {
2 Element node = (Element) list.get(i);
3 System.out.println("First Name : " +
4 node.getChildText("firstname"));
5 System.out.println("Last Name : " +
6 node.getChildText("lastname"));
7 }
7.最后,关闭try
语句块,并添加如下catch
语句块处理可能遇到的异常。
1 } catch (IOException io) {
2 System.out.println(io.getMessage());
3 } catch (JDOMException jdomex) {
4 System.out.println(jdomex.getMessage());
5 }
完整代码如下:
1import java.io.File;
2import java.io.IOException;
3import java.util.List;
4import org.jdom2.Document;
5import org.jdom2.Element;
6import org.jdom2.JDOMException;
7import org.jdom2.input.SAXBuilder;
8public class TestJdom {
9 public static void main(String[] args){
10 TestJdom test = new TestJdom();
11 test.parseXml("C:/dummyxml.com");
12 }
13 public void parseXml(String fileName){
14 SAXBuilder builder = new SAXBuilder();
15 File file = new File(fileName);
16 try {
17 Document document = (Document) builder.build(file);
18 Element rootNode = document.getRootElement();
19 List list = rootNode.getChildren("author");
20 for (int i = 0; i < list.size(); i++) {
21 Element node = (Element) list.get(i);
22 System.out.println("First Name : " +
23 node.getChildText("firstname"));
24 System.out.println("Last Name : " +
25 node.getChildText("lastname"));
26 }
27 } catch (IOException io) {
28 System.out.println(io.getMessage());
29 } catch (JDOMException jdomex) {
30 System.out.println(jdomex.getMessage());
31 }
32 }
33}
XML解析器类型多样,每种解析器都各有优点。Dom Parser。这种解析器会把文档的完整内容加载到内存中,并在内存中创建自己的层次树。SAX Parser:这种解析器不会把整个文档全部加载到内存中,文档的解析基于事件触发。JDOM Parser:JDOM解析器采用类似DOM解析器的方式解析文档,但是更加便捷。StAX Parser:这种解析器采用类似于SAX解析器的方式处理文档,但是效率更高。XPath Parser:这类解析器基于路径表达式来解析文档,经常与XSLT一起使用。DOM4J Parser:这是一个使用Java集合框架(该框架提供了对DOM、SAX、JAXP的支持)来解析XML、XPath、XSLT的Java库。
本文摘自《Java数据科学指南》
[加]鲁什迪·夏姆斯(Rushdi Shams) 著
点击封面购买纸书
学习MLlib、DL4j和Weka等开源库,掌握实用的Java数据科学技能
本书旨在通过Java编程来引导读者更好地完成数据科学任务。本书通过9章内容,详细地介绍了数据获取与清洗、索引的建立和检索数据、统计分析、数据学习、信息的提取、大数据处理、深度学习、数据可视化等重要主题。
- 点赞
- 收藏
- 关注作者
评论(0)