IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML | Java technology  >

高级 XQuery:创建自定义函数

将软件开发的最佳实际添加到 XQuery 表达式

developerWorks
前一页第 3 页,共 10 页后一页

文档选项

样例代码


对本教程的评价

帮助我们改进这些内容


编写您的第一个示例

现在我们通过示例进行学习。在这一小节,您将在一个模拟的 eCommerce 环境中实现一个 XQuery 函数。

了解您的业务

如前所述,您将在一个模拟的 eCommerce 环境中实现自己的 XQuery 函数。在这个例子中,您有一个在线业务,称为 fishinhole.com。这是一个营销钓具的 Web 站点。用户浏览产品目录,订购产品,然后指定收货地址。

常用的缩写词
  • API:应用程序编程接口
  • HTML:超文本标记语言
  • IDE:集成开发环境
  • W3C:万维网联盟
  • XML:可扩展标记语言

目录中包含的产品的信息以层次结构的形式存储在一个 XML 文档中。这个 XML 文档包含每个产品的信息,比如它的名称、价格、颜色、说明,以及发货时间。Web 应用程序获取这个 XML 文档并将其转换成可以在用户的浏览器上显示的 HTML 表示。

您将实现一个用于协助特定用例的 XQuery 表达式。在这个例子中,一个经过验证的用户想要在 Web 站点上执行搜索。该用户的目的是搜索一种现状像米诺鱼的鱼饵,并且要求能在特定的时间内收到货物(例如两天以内)。您将使用 XQuery 查询该 XML 文档并只返回符合条件的鱼饵。

XQuery 函数(已在 清单 1 中展示)用来根据用户的地理位置 一般的运输延误计算用户收到鱼饵所需的时间。这是很有必要的,因为 fishinhole.com 的产品销往世界各国,并且运输时间不仅受运输延迟的影响,也受目的地的影响。





回页首


XML 文件:fishinhole.xml

看看这个 XML 文件,您将在这个用例中解析和查询它。清单 4 展示了整个 XML 文档(随本教程附带)的一小部分。尽管为了节省空间对该 XML 文档进行了删减,但清单 4 已经足以显示数据的总体结构。


清单 4. XML 文档的结构
					<lures>
 <casting>
  <minnows brand="yohuri" style="deep" size="3">
   <minnow color="midnight blue">
    <international-prices>
     <price denomination="dollar">3.25</price>
     <price denomination="euro">4.25</price>
     <price denomination="canadian-dollar">4</price>
     <price denomination="peso">100</price>
    </international-prices>
    <availability>
     <shipping>
      <delay>0</delay>
     </shipping>
     <regions>
      <shipping-region>United States</shipping-region>
      <shipping-region>European Union</shipping-region>
      <shipping-region>Canada</shipping-region>
      <shipping-region>Mexico</shipping-region>
     </regions>
    </availability>
   </minnow>
  </minnows>
 </casting>
</lures>

清单 4 展示了一种鱼饵并提供了大量与之相关的信息。这些信息包括价格、运输方式、品牌名称、尺寸、样式和颜色。有些信息用属性进行描述,比如 brandstyle。其他信息使用嵌套元素进行描述,比如 <price>。注意,一些元素还对产品进行分类,比如 <casting><minnows>。这就是业务的数据结构。

尤其需要注意 <shipping> 元素。该元素的子元素是 <delay>,它描述运输延迟。前面的用例就用到这个数字。在 清单 4 的示例中,延迟为 0,它表示该产品可以在订购日达到。对于本例,运输延迟都是以天为计算单位的。





回页首


开始使用 Java 类文件

接下来,您将使用 Java 代码和 XQJ 编写 Java 类。您将编写一个简单的 Java 类,用作 XQuery 函数的单元测试。

调用这个类 XQueryFunctionTester。它将拥有一个构造函数,与 XML 文档的文件名同名。它还拥有一个 main() 方法,因此您可以执行它。清单 5 展示了这个类。


清单 5. 开始使用 Java 测试类
					
package com.triangleinformationsolutions.article.xquery;

import java.io.FileReader;
import java.util.Properties;

import javax.xml.namespace.QName;

import com.ddtek.xquery3.XQConnection;
import com.ddtek.xquery3.XQException;
import com.ddtek.xquery3.XQExpression;
import com.ddtek.xquery3.XQItemType;
import com.ddtek.xquery3.XQSequence;
import com.ddtek.xquery3.xqj.DDXQDataSource;

public class XQueryFunctionTester {

	private static final String XML_DOCUMENT  = "./fishinhole.xml";
	
	private String filename;

	
	public XQueryFunctionTester(String filename) {
		this.filename = filename;
	}

	
	private void go() {
	}
	
	
	public static void main(String[] args) {
		XQueryFunctionTester tester = new XQueryFunctionTester(XML_DOCUMENT);
		tester.go();
	}
}

我们先看一看 main() 方法。这是标准的 Java 应用程序的入口点。在这里,使用将要查询的 XML 文档的文件名实例化 XQueryFunctionTester。注意,我将 XML 文件置于 Java 类包结构的根部。要成功执行该类,就必须将它放到那个位置。我选择硬编码 XML 文档的引用,而不是使用命令行参数,因为使用 IDE 时,硬编码引用更加容易。如果发生了某些更改,我只需在代码上直接改动,然后重新执行。

go() 方法用于执行查询。实例化 XQueryFunctionTester 之后,就脱离了 main() 创建的静态上下文。我现在留空 go()。以后还要处理它。

此外,还要注意,我在这里包含了以后要用到的导入。这些内容大部分来自 XQJ 库,并且随后使用的 XQuery 搜索需要它们。QName 类根据 XML 规范指定一个限定名。FileReader 读取该 XML 文件。XQJ 实现需要 Properties 类。只有使用一个空的构造函数构造它,并将它作为一个方法参数传入之后才能使用它。

在这个测试用例中,用户将搜索运输延迟小于等于特定天数的所有米诺鱼诱饵。因此要编写执行该搜索的方法,如 清单 6 所示。


清单 6. 执行 XQuery 搜索的方法
					
private static final int SHIPPING_DELAY_IN_DAYS = 3;
private static final String DOCUMENT_NAME_FIELD = "docName";
private static final String SHIPPING_DELAY_FIELD = "shippingDelay";
private static final String MAXIMUM_DELAY_FIELD = "maximumDelay";


private XQExpression getGenericExpression() throws XQException {
	XQExpression expression = conn.createExpression();
	
	expression.bindString(new QName(DOCUMENT_NAME_FIELD), filename,
		conn.createAtomicType(XQItemType.XQBASETYPE_STRING));

	return expression;
}


private String getAllMinnowsWithMaximumDelay(int maximumDelay) throws Exception {
	XQExpression expression = getGenericExpression(); 

	expression.bindInt(new QName(SHIPPING_DELAY_FIELD), SHIPPING_DELAY_IN_DAYS,
		conn.createAtomicType(XQItemType.XQBASETYPE_INTEGER));	
	
	expression.bindInt(new QName(MAXIMUM_DELAY_FIELD), maximumDelay,
		conn.createAtomicType(XQItemType.XQBASETYPE_INTEGER));
	
	FileReader fileReader = new FileReader(GET_ALL_MINNOWS_WITH_MAX_DELAY_FILE);
	XQSequence results = expression.executeQuery(fileReader);
	
	return results.getSequenceAsString(new Properties());
}

简要地说,清单 6 中的两个方法构造了一个 XQExpression 对象,并执行它,然后以 String 格式返回结果。

getGenericExpression() 方法为扩展做好准备。如果您想在不同的测试中创建另一个方法,可以使用 getGenericExpression(),而不是为每个新的测试重新编写该方法。这个方法构造一个 XQExpression 对象并将 docName 字段设置为 XML 文件的名称。

getAllMinnowsWithMaximumDelay() 用于测试本文的用例。首先获取上面定义的泛型表达式,然后将某些变量绑定到在 Java 类中定义的值。第一个绑定的变量是 SHIPPING_DELAY_IN_DAYS,它表示虚构用户根据用户的地理位置收到货物所需的时间。在这个例子中,这个方法将变量设置为 3。下一个变量 MAXIMUM_DELAY_FIELD 是用户可以接受的最长运输时间。这个值从 maximumDelay 参数传入。最后,FileReader 读取 XQ 文件(后面将构建该文件)。这样,您就可以查询该文件并以 String 对象的形式返回结果。

注意,XQ 文件也位于类包的根部。即它和 XML 在同一个地方。

要获得更多关于 XQJ 的信息,请参阅 参考资料

清单 7 中,您将返回到 go() 方法,它执行实际的测试。


清单 7. go()init() 方法
					
private DDXQDataSource dataSource;
private XQConnection conn;

public void init() throws XQException {
	dataSource = new DDXQDataSource();
	conn = dataSource.getConnection();
}


private void go() {
	try {
		init();
		
		int delayToUse = 2;
		
		String returnedHtml = getAllMinnowsWithMaximumDelay(delayToUse);
		
		System.out.println(returnedHtml);
	} catch (Exception e) {
		e.printStackTrace();
	}
}


首先,go() 方法调用 init() 方法,后者构造 XQJ 数据源并从中创建一个 XQConnection 对象。其次,要确定虚构用户能够接受的最长运输延迟。在这里仅为两天。然后调用前面描述的方法 getAllMinnowsWithMaximumDelay(),并将 delayToUse 作为参数传入。最后,就可以输出结果了。





回页首


XQuery 文件:getAllMinnowsWithMaxDelay.xq

现在,可以看一看 XQ 文件了。如 清单 8 所示。这个文件包含搜索和检索 XQuery 表达式和 XQuery 函数。刚才创建的 Java 类将引用这个文件。


清单 8. XQuery 文件
					declare variable $docName as xs:string external;
declare variable $maximumDelay as xs:integer external;
declare variable $shippingDelay as xs:integer external;

declare function local:calculateReceivedIn($delay as xs:integer) 
{
	let $receivedIn := ($delay + $shippingDelay)
	return ($receivedIn)
}; 

for $minnows in doc($docName)//minnows
return
<div class="filterResults">
 <div class="brand">
	Brand: {data($minnows/@brand)}	
 </div>
 <div class="size">
	Size: {data($minnows/@size)} inches
 </div>
 {
 for $minnow in $minnows/minnow
 where $minnow/availability/shipping/delay<=$maximumDelay
 return
  <div class="singleFilterResult">
   <div class="color">
	Color: {data($minnow/@color)}
   </div>
   <div class="shippingInfo">
    <div class="receivedIn">
    Received in {local:calculateReceivedIn($minnow/availability/shipping/delay)} day(s)
    </div>
   </div>
  </div>
 }
</div>

这个 XQ 文件的总体目标是从 XML 文件提取与查询相匹配的元素,并将包含在这些元素中的信息呈现给用户。在这里,您可以在不同的类中使用一系列的 div 标记,该标记是在样式表文件中定义的。可以通过这种方式以可读美观的形式向用户呈现提取的信息。

看一看 XQ 文件的前 3 行。它们的变量名看上去很熟悉。因为您在 getAllMinnowsWithMaximumDelay()getGenericExpression() 方法中使用了这些名称。在这些方法中,值被绑定到这里定义的变量中。

接下来的几行也比较熟悉。这就是前面详细描述的函数。正是该函数返回货物运输延迟(传入的参数)和用户地理运输延迟(在文件的顶部定义的变量之一)之和。

然后是一个标准的 XQuery 表达式。这个表达式返回运输延迟天数小于等于 $maximumDelay 指定的天数的所有米诺鱼诱饵。

在代码的底部,要注意 XQuery calculateReceivedIn 函数的实现。这个函数首先使用一个标准的 XQuery 表达式提取 <delay> 元素的值,然后将这个值作为 calculateReceivedIn 函数所需的惟一参数传递。





回页首


综合

如果您已经综合这些函数,现在就可以下载本教程提供的文件了(参见 下载)。

您可以将本教程提供的压缩文件(.zip)提取到硬盘驱动器上的某个测试目录。该文件将 Java 源代码、XML 文件和 XQ 文件放到适当的位置。

接下来,编译 Java 源代码。您需要确保 ddxq.jar 在类路径中。这个库是 XQJ 发布版的一部分,它位于安装 XQJ 的目录下的 /lib 目录中。

如果编译没有问题,就可以运行这些代码了。在命令提示符处,转到刚才将代码解压缩到其中的目录,然后输入 java com.triangleinformationsolutions.article.xquery.XQueryFunctionTester 并使用适当的 -cp 参数指定指向 ddxq.jar 的类路径。只要 java.exe 在类路径中,它应该能够正常运行。

您很有可能从 IDE 运行它,而不是命令提示符。对于这种情况,只需根据 IDE 提供的指令执行一个独立的 Java 应用程序。

成功执行之后,输出结果应该类似于 清单 9。在本教程中,这个结果经过删减。


清单 9. 预期输出结果(经过删减)
					<div class="filterResults">
 <div class="brand">
  Brand: Yohuri
 </div>
 <div class="size">
  Size: 3 inches
 </div>
 <div class="singleFilterResult">
  <div class="color">
   Color: midnight blue
  </div>
  <div class="shippingInfo">
   <div class="receivedIn">
    Received in 3 day(s)
   </div>
  </div>
 </div>
 <div class="singleFilterResult">
  <div class="color">
   Color: clown
  </div>
  <div class="shippingInfo">
   <div class="receivedIn">
    Received in 4 day(s)
   </div>
  </div>
 </div>
</div>

如果将 XML 文档和 清单 9 中的输出相比,您将发现它是正确的。深蓝色的鱼饵没有运输延迟(或 0 天延迟)。将它与和 $shippingDelay(该值为 3,如以上的 Java 代码所示)绑定的值相加就等于 3。杂色的鱼饵有 1 天的延迟。它和 3 相加就等于 4,所以运输延迟时间为 Received in 4 day(s)。换句话说,这个测试是成功的!





回页首



前一页第 3 页,共 10 页后一页
    关于 IBM 隐私条约 联系 IBM 使用条款