动网论坛,站长建站首选,国内使用量最多的论坛软件 动网论坛官方技术讨论区 站长工具 申请属于您自己的免费论坛
首页 | 新闻资讯 | 网站运营 | 网络编程 | 数据库 | 服务器 | 网页设计 | 图像媒体 | 网络应用 | 搜索优化 | 资源下载 | 动网主机 | DVBOX
    本站内  互联网 ASP论坛  ASP.Net论坛  PHP论坛
   Xml → 阅读文章

 XPath在无线应用中的实现(下)

作者来源: 
阅读 1236 人次 , 2006-4-19 17:36:00 


  在本文的第一部分中,我们介绍了XPath并讨论了各种各样的从简单到复杂的XPath查询。 通过把XPath查询应用到XML示例文件,我们详细说明了各种重要的XPath定义比如location step、context node、location path、axes和node - test。 我们然后讨论了多个简单查询组合成的复杂的XPath查询。 我们还讨论了无线二进制XML(WBXML)--XML在无线应用领域的对应物--的抽象结构。 最后我们介绍一个简单的XPath处理引擎的设计。

  在这一部分里,我们打算讨论XPath的更进一步的特性--在一个XML文件上执行复杂检索的操作。 我们将讨论谓词或者过滤器查询以及在XPath中的函数的使用。我们将介绍各种的用于处理WSDL和WML的XPath查询。 我们还将增强我们的XPath引擎的功能,使之包括谓词、函数和不同的数据类型。

  过滤查询和谓词

  让我们从一个将返回任何XML文件当中的根节点的简单查询开始:

  ./node()

  我们可以更进一步,使用另一个简单查询,选择根节点的全部的直接子节点:

  ./node()/*

  如果你想要得到所有的是根节点的直接子节点并且只有一个type属性的节点,那么该怎么办呢? 那么就使用下面的这个查询:

  ./node()/*[attribute::type]
 
  在代码段1中,这个查询将返回binding元素。 由此可见,写在方括号之内的代码attribute::query担负一个过滤器的功能。 XPath中的过滤器被称作谓词(predicate),写在方括号内。 一个谓词作用在一个结点集上--在这个例子中,结点集由根节点的所有的直接子节点组成---应用过滤条件(在这里,结点肯定有一个type属性)到结点集上。 产生的结果就是一个经过过滤的结点集。

  谓词可以从简单到很复杂。 也许XPath谓词的简单形式就像下面的查询中的只是一个数字,返回根元素的第二个子节点(message元素):

  ./node()/*[2]

  查询语句./node()/message[attribute::name="TotalBill"]/text() 将寻找根元素的一个属性name值为TotalBill的特定的message子节点。 查询将返回特定的message元素的所有文本结点。 这个查询将返回代码段1中两个message元素中的第二个。

  XPath 函数

  假定你想要回答下面对代码段1中的WSDL文件所提出的问题:

  1. 最后一个operation元素的name属性的值是什么?

  2.定义元素有多少个message子元素?

  3. 根元素的第一个子元素的名称是什么?

  last()函数

  last()函数将总是指向结点集的最后一个结点。 下面的这个查询,当被应用于代码段1中的WSDL文件的时候,将返回第二message元素(即 名称是TotalBill的message元素):

  ./node()/message[last()]

  注意下面的这条查询也返回相同的message元素:

  ./node()/message[2]

  这两个查询之间唯一的区别就是我们使用数字2来代替last()方法。 事实上在本例中last()函数返回的值就是2(特定location step的结点集中的结点数)。 把这两个相同的查询应用到代码段2中的WSDL文件,这次你会发现两个查询没有返回相同的结果。 代码段2中有三个message元素,所以现在last()函数返回数字3。
注意本讨论中的last()函数总是返回一个数字。

  position()函数

  如果你把下面的这些查询应用到代码段2中的WSDL文件,

  ./node()/message[1]/part

  ./node()/message[2]/part

  ./node()/message[3]/part

  它们将分别返回message元素的第一个、第二个和第三个part子元素。 由此可见节点集中的每个节点都有一个位置。 第一个节点的位置是1,第二个节点的位置是2,以此类推。

  如果你想要得到除第二个以外的所有的message元素,你该怎么办? 你可以使用position()函数取得一个节点的位置。 下面的这条查询将返回代码段2中的第一个和第三个message元素:

  ./node()/message[position()!=2]

  position()函数只是返回指定值所表示的节点的位置。 谓词[position()!=2] 把所有的message元素的位置和2做比较,然后找出位置不是2的节点。
  count()函数
  
  代码段1中的portType元素有多少个message子元素? 数一数你就发现有两个message元素。 在XPath中解决"多少个"这种问题是一个二步的操作。 首先,写一个用来找到你想要统计的所有的子元素的XPath查询。 然后地像下面给出的那样,把 XPath查询传送到count()函数中:

  步骤1: ./node()/message

  步骤2: count(./node()/message)

  count()函数统计XPath查询所得到的节点集中的节点数,并返回这个节点数。

  name()、local-name()和namespace-uri()函数

  如果把下面的查询应用到代码段1中的WSDL文件的话,那么会出现什么情况呢?

  ./node()/*[5]

  它返回根元素的第五个子元素(即service元素)。 service元素本身是一个完整结构,也包含子元素。 因此,这个XPath查询的返回值实际上是一个XML节点而不仅仅是一个元素名。

  name()函数返回XML节点的名称。 例如,下面的查询应用到代码段1中将返回字符串"service":

  name(./node()/*[5])

  同样,下面的查询将返回字符串"wsd:definitions"(使用域名空间前缀的根元素的全名):

  name(./node())

  local-name()和namespace-uri()函数与name()函数类似,除了local-name方法只返回不带域名空间前缀的元素的局部名称,而namespace-uri函数仅仅返回域名空间URI。举例来说,请在代码段1中试验下面的查询:

  local-name(./node())

  namespace-uri(./node())

  第一个查询返回一个字符串" definitions",而第二个查询返回" http://schemas.xmlsoap.org/wsdl/ "。

  String函数

  我们已经知道name()、local-name()和namespace-uri()函数返回字符串。 XPath提供了许多函数用于处理字符串,比如string()、 substring()、substring-before()、 substring-after()、 concat()、starts-with()等等。 下面给出了一个例子来演示一下如何使用string()函数:

  string(./node()/*[2]/part/attribute::name)

  上面的这条查询将寻找根元素的第二个子元素,然后它将得到根元素的第二子元素的所有的part子元素。 接着它将寻找part子元素的name属性,最后它把name属性的值转换为一个字符串格式。 当把这条语句应用到代码段1中的时候,它将输出bill。

  XPath也提供一些布尔函数,返回"true/false",研究一下下面的这条查询:

  boolean(./node()/message)

  当把它应用到代码段1的时候,它返回true。 这是因为boolean()函数判断一个XPath查询产生的节点集是否为空(在我们的例子中,根元素包含两个message子元素)。 如果是空,boolean()函数返回false,否则返回true。 一个复杂的WSDL处理实例

  下面的WSDL处理方案使用了我们前面讨论过的所有的XPath概念。 这个方案的检索要求如下:

  寻找一个service元素,这个元素是definitions元素(根元素)的一个直接子元素,并且name属性与definitions元素的name属性匹配。 然后察看service元素,寻找一个port元素,这个port元素的binding属性与definitions元素的直接子元素binding的name属性匹配。

  这个WSDL过程可以用四步完成:

  1. 查找definitions元素的name属性值。 下面给出的XPath查询(从代码段中返回字符串BillingService)执行这步操作:

  string(//node()[1]/@name)

  2. 然后查找name属性匹配definitions元素的name的service元素。 下面的查询将返回所需要的service元素:

  ./node()[1]/service[@name=string(//node()[1]/@name)]

  3. 然后查找binding元素的name属性值:

  string(//node()[1]/binding/@name)

  4. 最后寻找需要的port元素:

  ./node()[1]/service[@name=string(//node()[1]/@name)]

  /port[@binding=string(//node()[1]/binding/@name)]

  这个实例说明XPath谓词可以包含简单逻辑条件,函数调用乃至完整的XPath查询。

  使用XPath处理WML

  WML是WAP Forum定义的一种XML语言。 WML为小型设备的显示提供了一种表现格式。 WML对于一个小型设备就好像HTML对于一台个人电脑一样。

  想象一下,一个WML文件是由一组卡片(card)组成,每个卡片由一个card元素封装。 代码段3是一个简单WML文件,只包含两个card元素。

  下面的XPath查询将返回代码段3中包含在第一个卡片之内(这卡片id是" first")的所有的p(paragraph)元素:

  ./node()/card[string(@id)="first"]/p

  下面这个查询返回第二个卡片中的第一段的文本内容:

  string(./node()/card[string(@id)="second"]/p[1]/text())

  实现XPath谓词与函数

  我们现在将看看如何在我们前面的那个简单的XPath引擎中插入谓词与函数的支持。

  四个伪代码类XPathExpression(代码段4)、XPathLocationStep(代码段5)、XPathResult(代码段6)和Predicate(代码段7)组成了支持谓词与函数的更新的版本。 我们在上一篇文章介绍的XPath引擎的基础上,增加了下列功能,使之更加强大:

  1. XPath可以返回各种类型的数据。 XPath可以返回节点、字符串、数字和布尔变量。 我们设计的XPath引擎只支持XML节点作为返回数据类型。 我们现在已经提供了一个名为XPathResult(见代码段6)的类来支持不同的数据类型。 基于我们的设计的实现需要扩展为每种数据类型分别地扩展XPathResult。

  2. 更新的设计现在包括一个支撑函数的结构。 一个函数调用可以发生在一个XPath查询开始时,也可以发生在任何XPath location step。 因此,XPathExpression类(代码段4)和XPathLocationStep类(代码段5)现在都添加了对函数调用的支持。

  3. 我们还提供了一个单独的类用于支持谓词(见代码段7)。 一个谓词可以只由一个逻辑条件组成也可以由一个完整的XPath查询组成。 因此,Predicate类构造器将判断谓词到底是一个完整的查询还是仅仅只是一个条件。 如果是一个完整的XPath查询,Predicate表达式将实例化一个新的XPathExpression对象,否则它将只是取得逻辑条件的值。

  小结

  在前面,我们讨论XPath中谓词与函数的语法和使用。 我们介绍WSDL和WML处理的实例并说明了如何构成更加复杂的XPath查询。 最后,我们增强了在第一篇文章中介绍的XPath引擎的功能。 代码段1:

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

<wsd:definitions name="BillingService"
targetNamespace="http://www.ElectricSupplyCompany.com/BillingService-interface"
xmlns:wsd="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ElectricSupplyCompany.com/BillingService"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<message name="MonthNumber">
 <part name="number" type="xsd:int"/>
</message>

<message name="TotalBill">
 <part name="bill" type="xsd:int"/>
</message>

<portType name="BillingService_port">
 <operation name="getBillForMonth">
  <input message="MonthNumber"/>
  <output message="TotalBill"/>
 </operation>
 <operation name="getCurrentBill">
  <output message="TotalBill"/>
 </operation>
</portType>

<binding name="BillingService_Binding" type="BillingService_port">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http" />
 <operation name="getBillForMonth">
  <soap:operation soapAction="urn:BillingService" />
  <input>
   <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:BillingService"
use="encoded" />
  </input>
  <output>
   <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:BillingService"
use="encoded" />
  </output>
 </operation>

 <operation name="getCurrentBill">
  <soap:operation soapAction="urn:BillingService" />
  <input>
   <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:BillingService"
use="encoded" />
  </input>
  <output>
   <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:BillingService"
use="encoded" />
  </output>
 </operation>

</binding>

<service name="BillingService">
 <documentation> Billing Service of Electric Supply Company. </documentation>
 <port binding="BillingService_Binding" name="BillingService_ServicePort">
 <soap:address location="http://localhost:8080/soap/servlet/rpcrouter" />
 </port>
</service>

</wsd:definitions>

  代码段2:

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

<wsd:definitions name="BillingService"
targetNamespace="http://www.ElectricSupplyCompany.com/BillingService-interface"
xmlns:wsd="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ElectricSupplyCompany.com/BillingService"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<message name="MonthNumber">
 <part name="number" type="xsd:int"/>
</message>

<message name="TotalBill">
 <part name="bill" type="xsd:int"/>
</message>

<message name="DetailedStatement">
 <part name="statement" type="xsd:string"/>
</message>

<portType name="BillingService_port">
 <operation name="getBillForMonth">
  <input message="MonthNumber"/>
  <output message="TotalBill"/>
 </operation>
 <operation name="getCurrentBill">
  <output message="TotalBill"/>
 </operation>
</portType>

<binding name="BillingService_Binding" type="BillingService_port">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http" />
 <operation name="getBillForMonth">
  <soap:operation soapAction="urn:BillingService" />
  <input>
   <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:BillingService"
use="encoded" />
  </input>
  <output>
   <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:BillingService"
use="encoded" />
  </output>
</operation>

<operation name="getCurrentBill">
 <soap:operation soapAction="urn:BillingService" />
 <input>
  <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:BillingService"
use="encoded" />
 </input>
 <output>
  <soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:BillingService"
use="encoded" />
 </output>
</operation>

</binding>

<service name="BillingService">
<documentation> Billing Service of Electric Supply Company. </documentation>
<port binding="BillingService_Binding"
name="BillingService_ServicePort">
<soap:address
location="http://localhost:8080/soap/servlet/rpcrouter" />
</port>
</service>

</wsd:definitions>
代码段3:

<?xml version="1.0" encoding="UTF-8" ?>
<wml>
 <!--简单的WML文件-->
 <card id="first">
  <p>
   First card.
  </p>
 </card>
 <card id="second">
  <p>
   First para of the Second card.
  </p>

  <p>
   Second para of the Second card.
  </p>

 </card>
 <!--可以在下面放入其它的card-->
</wml>

  代码段4:

public class XPathExpression
{
 DOM_Document XML_DOM;
 Array of Strings XPathLocationStepStringsArray;
 Array of XPathLocationSteps XPathLocationStepsArray;
 Array of XPathResults ResultNodeSet;

 XPathExpression (string XMLFile, string XPathExpression)
 {
  XML_DOM = XMLFile loaded into a DOM;
  FunctionName =
If there is any XPath function in the begining of the query,
store the function name here;
Strip the function name from the expression.

  XPathLocationStepStringsArray =
Tokenize XPath expression into smaller strings,
where each string is a location step.
Also unabbreviate any XPath abbreviations found;

  Integer locationStepCount = Number of location step strings
in XPathLocationStepStringsArray;
String IndividualXPathLocationStepString;
XPathLocationStep IndividualXPathLocationStep;

  ResultNodeSet = XML_DOM loaded into an array of XPathResults.

  Repeat locationStepCount times from i = 0 to locationStepCount-1:
  {
   IndividualXPathLocationStepString = XPathLocationStepStringsArray[i];
   IndividualXPathLocationStep = a new object of XPathLocationStep(
                  IndividualXPathLocationStepString,
                  XML_DOM
   );
   ResultNodeSet = IndividualXPathLocationStep.getResult(ResultNodeSet);
  }

  Apply the XPath function on the resulting node-set

 }

 XPathExpression (DOM_Document XML_DOM, string XPathExpression)
 {
  Same as the first constructor,
  except that it takes the XML file as a
  DOM object instead of a string.

 }

 public Array of XPathResults getResult()
 {
  return ResultNodeSet;
 }
}

  代码段5:

public class XPathLocationStep
{
 String Axis;
 String NodeTest;
 Array of XPathResults OutputNodeSet;
 String FunctionName;
 String Predicate;
 DOM_Document XML_DOM;

 XPathLocationStep(String XPathLocationStepString, DOM_Document XML_DOM_Document)
 {
  Resolve the XPathLocationStepString into FunctionName,
  Axis, NodeTest, and Predicate;
  XML_DOM = XML_DOM_Document;
 }

 Array of XPathResults getResult(Array of Nodes ContextNodeSet)
 {
  OutputNodeSet = new Array of XPathResults;

  Integer NodeCount =Number of nodes in ContextNodeSet;
  if (Axis is equal to "child" or "descendant")
  {
   Repeat NodeCount times for i = 0 to NodeCount-1
   {
    Node node = ContextNodeSet[i];
    Integer ChildCount = Number of node's children;
    Repeat ChildCount times for j = 0 to ChildCount-1
    {
     Node ChildNode =node.getChildElement(j);
     String ChldName =Name of the ChildNode;
     if (NodeTest is equal to ChildName)
      Add ChildNode to OutputNodeSet;
     if (Axis is equal to "descendant")
     {
      Array of Nodes Descendants =getMatchingDescendants(ChildNode);
      Add MatchingDescendants to OutputNodeSet;
     }
    }
   }
  }

  Predicate predicateEvaluator = new Predicate(OutputNodeSet, XML_DOM);
  OutputNodeSet = predicateEvaluator.getResult();
  return OutputNodeSet;

 }

 private Array of Nodes getMatchingDescendants(Node node)
 {
  Array of Nodes MatchingDescendants;
  Integer ChildCount = Number of node's children;
  Repeat NodeCount times for j = 0 to ChildCount-1
  {
   Node ChildNode =node.getChildElement(j);
   String ChildName =Name of the ChildNode;
   if (NodeTest is equal to ChildName)
    Add ChildNode to MatchingDescendants;

   Array of Nodes MoreDescendants =getMatchingDescendants(ChildNode);
   Add MoreDescendants to MatchingDescendnts;
  }
  return MatchingDescendants;
 }

}

  代码段6:

public class XPathResult
{ string ResultType = "ArrayOfNodes";

 string getResultType
 {
  return ResultType;

 }

 public setResultType (string Type)
 {
  ResultType = Type;
 }
}

  代码段7:

public class Predicate
{
 Array of XPathResults ResultSet;

 Predicate(Array of XPathResults ResultSet,
 DOM_Document XML_DOM)
 {
  Check if this predicate is just a logical condition or a complete XPath query.
  If it is a complete XPath expression
  {
   ResultSet = (new XPathExpression(XML_DOM, XPath Expression))
   .getResult();
  }
  else
  {
   ResultSet = Filtered result set;
  }
 
 }

 Array of XPathResults getResult()
 {
  return ResultSet;
 }

}
  
 
 收藏本文  打印本文  论坛讨论  关闭窗口
· 上一篇:2005年 Web2.0 带动的11大软件
· 下一篇:学AJAX代步能否跟上技术的发展
· 教您使用XML封装数据库操作语句的实现
· 在.NET Framework中轻松处理XML数据(5-2)
· XML简易教程之一
· XSLT轻松入门第三章:XSLT的元素语法(1)
· SQL Server XML 和 Web 应用体系结构(一)


关于本站 | 联系我们 | 业务合作 | 客户案例 | 诚聘英才 | 广告合作 | 收藏本站
海口动网先锋网络科技有限公司版权所有
Copyright © 2000 - 2006 Cndw.Com
中华人民共和国电信与信息服务业务经营许可证编号 琼 ICP 020077