从 XPath 到 SPL

XML 的多层结构计算起来难度较大,XPath 的计算能力严重不足,只能在计算需求较弱的互联网应用早期发挥作用,如今的计算需求日益复杂多变,需要 SPL 这种能力更强的 XML 计算语言。点击从 XPath 到 SPL了解详情。

XML可灵活表达数据,又有跨平台的特点,广泛应用于Web交换服务和数据服务,比如WebService。但多层的XML结构复杂,计算起来不方便,这种情况下就要用到XML计算语言。在XML标准被W3C提出的第二年,首款XML计算语言XPathXQuery)就应运而生了。XPathXML计算方面可以显著提高开发效率,这使它迅速受到了开发者的热捧,很快被引入主流XML解析类库中,比如XOM/Xerces-J/Jdom/Dom4J

下面让我们看两个例子,体会一下XPath当年的计算能力。

文件Employees_Orders.xml存储一批员工信息,以及属于员工的多个订单,部分数据如下:

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

<xml>

<row>

         <EId>2</EId>

         <State>"New   York"</State>

         <Dept>"Finance"</Dept>

         <Name>"Ashley"</Name>

         <Gender>"F"</Gender>

         <Salary>11000</Salary>

         <Birthday>"1980-07-19"</Birthday>

<Orders>[]</Orders>

</row>

<row>

         <EId>3</EId>

         <State>"New   Mexico"</State>

         <Dept>"Sales"</Dept>

         <Name>"Rachel"</Name>

         <Gender>"F"</Gender>

         <Salary>9000</Salary>

         <Birthday>"1970-12-17"</Birthday>

         <Orders>

                  <OrderID>32</OrderID>

                  <Client>"JFS"</Client>

                  <SellerId>3</SellerId>

                  <Amount>468.0</Amount>

                  <OrderDate>"2009-08-13"</OrderDate>

         </Orders>

         <Orders>

                  <OrderID>39</OrderID>

                  <Client>"NR"</Client>

                  <SellerId>3</SellerId>

                  <Amount>3016.0</Amount>

                  <OrderDate>"2010-08-21"</OrderDate>

                  </Orders>

         <Orders>

</row>

<xml>

条件查询:针对该XML文件,用Dom4J解析类库的XPath查询出所有价格在1000-3000,且客户名包含bro字样的订单。核心代码如下:

      …

         SAXReader saxReader =   SAXReader.createDefault();

         Document doc =   saxReader.read("file:\\D:\\xml\\Employees_Orders.xml");

         List<Node>   list=doc.selectNodes("/xml/row/Orders[Amount>1000 and Amount<=3000   and contains(Client,'bro')]")

         int i=0;

          System.out.println("--------------count of the current   resultSet="+list.size());

        for(Node n:list){

            String   OrderID=n.selectSingleNode("./OrderID").getText();

            String   Client=n.selectSingleNode("./Client").getText();

            String   SellerId=n.selectSingleNode("./SellerId").getText();

            String   Amount=n.selectSingleNode("./Amount").getText();

            String   OrderDate=n.selectSingleNode("./OrderDate").getText();

System.out.println(++i+":"+OrderID+"\t"+Client+"\t"+SellerId+"\t"+Amount+"\t"+OrderDate);

        }

XPath语句中里/xml/row/Orders 是查询范围,Amount>1000 and Amount<=3000 and contains(Client,'bro')是查询条件,函数contains可进行模糊查询。XPath的函数分四类,数学函数有absfloor,字符串函数如comparesubstring,日期函数如year-from-datetimezone-from-time,还有一种聚合函数,下面正要讲到。

聚合计算:针对该XML文件,计算出总的订单金额。核心代码如下:

    list=doc.selectNodes("sum(/xml/row/Orders/Amount)");

    Object sumResult=list.get(0);

      System.out.println((Double)sumResult);

代码中使用了聚合函数sum,类似的函数XPath还有4个,分别是count\max\min\avg

从上面两个例子可以看到XPathXML计算方面的优点:代码简短直观,可以用点号方便地访问多层结构;对条件查询和聚合计算的支持较为完善,提供了较为丰富的库函数

在计算需求较弱的互联网应用早期,XPath凭借上述优点深受开发者的追捧,但随着计算需求越来越多样化和复杂化XPath的缺点也逐渐显露出来。

计算能力不足XPath最致命的缺点。前面提到XPath支持条件查询和聚合,换个说法就是XPath只支持这两种最简单的计算,其他大量的常规计算则全都不支持,比如排序、归并、唯一、分组汇总、关联计算、分组后计算(含窗口函数)等等。再说XPath的库函数,表面上虽然数量不少,但真正可用于计算的函数就只有5个聚合函数,可以用少得可怜来形容。由于XPath不支持子查询和分步骤计算,对较复杂的计算目标更是无能为力。事实上,对于近几年的XML计算需求而言,XPath只能起到辅助的作用,大量的计算都要用硬编码完成。

除了计算能力之外,XPath还有数据源接口少的问题。XPath只有文件数据源接口,不支持WebService/HTTP,而后者才是XML的主要来源。

如今的计算需求越来越多样化和复杂化,难道开发者只能忍受计算能力不足的XPath,难道就没有计算能力更强的XML计算语言了吗?

         集算器 SPL是个更好的选择。

集算器 SPL是专业的结构化/半结构化数据计算语言,内置丰富的计算函数,可以用简短的代码实现所有的常规计算,可将大计算目标分解为多个小步骤,支持多种数据源接口,同时提供JDBC集成接口。SPL可以用统一的语法和数据结构计算各类数据源,其中就包括XML

对于前面的条件查询,只需如下SPL代码即可实现:


A

1

=xml(file("D:\\xml\\Employees_Orders.xml").read(),"xml/row")

2

=A1.conj(Orders)

3

=A2.select(Amount>100 &&   Amount<=3000 && like@c(Client,"*bro*"))

上面代码先将XML读为多层的序表对象,再用conj函数合并所有订单,之后用select函数完成条件查询。

这段代码可在SPLIDE中调试/执行,也可存为脚本文件(比如condition.dfx),通过SPLJDBC接口在JAVA中调用,具体代码如下:

package Test;
  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.ResultSet;
  import java.sql.Statement;
  public class test1 {
      public static void main(String[]   args)throws Exception {
            Class.forName("com.esproc.jdbc.InternalDriver");
          Connection connection   =DriverManager.getConnection("jdbc:esproc:local://");
          Statement statement =   connection.createStatement();
          ResultSet result =   statement.executeQuery("call condition()");
          printResult(result);
          if(connection != null)   connection.close();
      }

}

再看几个例子。聚合计算

=A2.sum(Amount)

排序:

=A1.sort(Dept,-Salary)

分组汇总

=A2.groups(year(OrderDate);sum(Amount))

    关联计算

=A1.new(Name,Gender,Dept,Orders.OrderID,Orders.Client,Orders.SellerId,Orders.Amount,Orders.OrderDate)

从上面代码可以看出,SPL计算能力更强,不仅可以完成常用的计算,且代码简短易懂,与JAVA集成时耦合性更低。特别地,序表类型天然支持多层数据,可以用点操作符直观表达层级关系,特别适合XML

SPL计算能力更强,经常可以简化多层XML的计算。比如文件book1.xml存储图书信息,其中作者节点有作者名、国籍这两个属性,且有些书有多个作者,部分数据如下:

<?xml version="1.0"?>

<library>

    <book   category="COOKING">

        <title>Everyday Italian</title>

        <author   name="Giada De Laurentiis" country="it" />

          <year>2005</year>

        <info>Hello   Italian!</info>

    </book>

    <book   category="CHILDREN">

        <title>Harry Potter</title>

        <author name="J K.   Rowling" country="uk"/>

        <year>2005</year>

        <info>Hello   Potter!</info>

    </book>

    <book   category="WEB">

        <title>XQuery Kick Start</title>

          <author name="James McGovern" country="us"   />

          <author name="Per Bothner" country="us"/>

          <year>2005</year>

        <info>Hello   XQuery</info>

    </book>

    <book   category="WEB">

        <title>Learning XML</title>

        <author name="Erik   T. Ray" country="us"/>

          <year>2003</year>

        <info>Hello   XML!</info>

    </book>

</library>

将这个XML整理成结构化二维表,其中作者字段以“作者名[国籍]”的格式呈现,如果某本书有多个作者,则以逗号分隔。最后查询该表,选出2005年的图书信息。结果应当如下:

title

category

year

Author

info

Everyday Italian

COOKING

2005

Giada De Laurentiis[it]

Hello Italian!

Harry Potter

CHILDREN

2005

J K. Rowling[uk]

Hello Potter!

XQuery Kick Start

WEB

2005

James McGovern[us],Per Bothner[us]

Hello XQuery

这道题有一定难度,用SPL来计算可以明显简化,具体代码如下:


A

1

=file("D:\\xml\\book1.xml")

2

=xml@s(A1.read(),"library/book").library

3

=A2.new(category,book.field("year").ifn():year,book.field("title").ifn():title,book.field("lang").ifn():lang,book.field("info").ifn():info,book.field("name").select(~).concat@c():name,book.field("country").select(~).concat(","):country)

4

=A3.new(title,category,year,(lang,name.array().(~+"[")++country.array().(~+"]")).concat@c():author,info)

5

=A4.select(year==2005)

除了计算能力,SPLWebService/HTTP等数据源的支持也较好,比如从WebService取天气预报的接口描述,再根据接口描述查询省份列表,并返回XML结果:


A

1

=ws_client("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl")

2

=ws_call(A1,"WeatherWebService":"WeatherWebServiceSoap":"getSupportProvince")

 

作为第一款XML计算语言,XPath曾经做出过突破性的贡献,但计算能力不足始终是致命缺点。在计算需求日益多变的今天,唯有SPL这种能力更强的XML计算语言,才能继续提供较高的开发效率。