JXpath学习笔记

最近学习了下Apache Commons项目下的一个子项目JXpath的使用,结合官方文档与网络上的一些入门教程小试用了一把。下面把学习内容整理了下,以便日后查看。

1      简介

JXPath定义了一个简单的XPath解释器,可用于定位各种对象——JavaBeans, Maps, Servlet contexts, DOM——以及它们的混合。

JXPath的核心类是JXPathContext,所以应用几乎总是会用到该类。

2      应用及示例

下面我们用一个示例来说明其应用,示例使用 Company --> Department --> Employee的结构来展示JXPath的应用。

Company

Department

Employee

String name;

List<Department> departments;

String name;

Set<Employee> employees;

String name;

int age;

Map<String, String> contacts

Company[“MS”]:

  Department[“Development”]

  Department[“Administrative”]

Department[Development]:

  Employee[“Eric”]

Employee[“Andy”]

Department[Administrative]:

  Employee[“Lily”]

  Employee[“Lucy”]

Employee[“Eric”]:

  age: 20

  contacts:

<home, “1234567”>

<office, “7654321”>

Employee[“Andy”]:

  age: 28

Employee[“Lily”]

  age: 22

Employee[“Lucy”]

  age: 25

我们共用一个JXPathContext,如下:

JXPathContext context = JXPathContext.newContext( company );

2.1      选取当前节点

Company c = (Company) context.getValue( "." );

由于我们使用的company创建的JXPathContext,所以,company是根节点,也是当前节点。使用“.”选择器就可以选取当前节点,即company。表达式 c == company 也会返回true

2.2      访问属性

String companyName = (String) context.getValue( "name" );

当前节点companyname属性,所以可得company name—— MS

2.3      谓语

Employee lily = (Employee) context.getValue( "/departments/employees[name='Lily']" );

谓语类似于SQL中的WHERE语句,有筛选作用,谓语被嵌在方括号中。以上代码可以选出所有部门所有员工中叫“Lily”的员工。

谓语中可以使用运算符。

context.getValue( "/departments/employees[name='Lily1' or age=22]" );

context.getValue( "/departments/employees[name='Lily' and age=22]" );

 

2.4      变量

context.getVariables().declareVariable( "name", "Eric" );

Employee eric = (Employee) context.getValue( "/departments/employees[name=$name]" );

查询中是可以使用变量的,只需要取得context关联的变量池,声明变量即可。

引用变量时,只需要在变量名前加前导符“$”即可。

声明的变量不必是字符串,可以是任意对象。

2.5      宽松模式

context.setLenient( true );

Employee clark = (Employee) context.getValue( "/departments/employees[name='clark']" );

如果指定的xpath不能映射到任何已存在的节点,那么将抛出异常。但是,这个限制在调用context.setLenient( true );后将被放宽,仅返回null,而不抛出异常。

2.6      访问Map

context.getValue( "/departments/employees[name='Eric']/contacts/home" );

context.getValue( "/departments/employees[name='Eric']/contacts[@name='office']" );

我们知道Employee类中有contacts属性,为Map类型。名为Eric的员工存储了两种联系方式:homeoffice。上面的代码分别用两种语法选取了两种联系方式。

JXPath只支持key为字符串的Map

2.7      访问集合

2.7.1       迭代单个集合

                   for ( Iterator<?> iter = context.iterate( "/departments" ); iter.hasNext();  )

                   {

                            Department dept = (Department) iter.next();

                            System.out.println(dept.getName());

                   }

上面的代码会得到company下的departments的迭代器,即可遍历所有部门。

2.7.2       迭代多个集合

                   for ( Iterator<?> iter = context.iterate( "/departments/employees" ); iter.hasNext(); )

                   {

                            Employee emp = (Employee) iter.next();

                            System.out.println(emp.getName());

                   }

与迭代单个集合不同,上面的代码选取的节点不只是一个集合,它选取了所有部门下的所有员工集合。但是返回的迭代器可以一次性迭代遍历所有员工,尽管他们在不同部门的员工集合中。

2.7.3       下标

Employee emp2 = (Employee) context.getValue( "/departments/employees[2]" );

对于数组或集合形式的节点,我们可以使用下标的方式进行访问。

Set这种无序的集合而言,它的元素顺序是其迭代顺序,由于迭代顺序是不可预测的,所以通常不会使用下标访问Set

注:下标是从1开始,而不是0

下标访问时,根据迭代多个集合的思维来预测结果会有一些偏差。

对上面代码而言,并没有把所有部门的员工合并,然后选取第2个员工。相反,程序将进行路径尝试。首先,尝试 /departments[1]/employees[2]能否选取节点,如果可以返回该节点;如果不能则尝试 /departments[2]/employees[2]能否选取节点……以此类推。所以,上面代码返回的结果应是查找到的第1个至少有2个员工的部门的第2个员工。

以上说明的是getValue()的行为,但是对于iterate()又有点不同。

              for ( Iterator<?> iter = context.iterate( "/departments/employees[2]" ); iter.hasNext(); )

              {

                     Employee emp = (Employee) iter.next();

                     System.out.println(emp.getName());

              }

相同的是,iterate()也会进行路径尝试,但不同在于它会返回所有尝试通过的节点的集合的迭代器。对上面的代码而言,返回的迭代器对应的集合应该是所有至少拥有2个员工的部门下的第2个员工的集合。本例中,Development部门有AndyEricAdministrative部门有LucyLily——员工按顺序列出的——那么迭代出的员工应是EricLily

 

【参考】

http://www.javaworld.com/article/2077700/data-storage/java-object-queries-using-jxpath.html

你可能感兴趣的:(xpath)