首页 > 代码库 > XQuery元素构造,你知道多少?

XQuery元素构造,你知道多少?

今天遇到一个问题,对于下面这样一个xml串
<opDetail>
    <recordInfo>
        <fieldInfo>
            <fieldChName>告警流水号</fieldChName>
            <fieldEnName>alarmId</fieldEnName>            
            <fieldContent>GJ_2816071613_352385154_2970760107_588354443</fieldContent>
        </fieldInfo>
        <fieldInfo>
            <fieldChName>告警ID</fieldChName>
            <fieldEnName>alarmStaId</fieldEnName>
            <fieldContent>2014070200101</fieldContent>
        </fieldInfo>
   </recordInfo>
</opDetail>
如何转换成下面这种形式:
<opDetail>
    <recordInfo>
        <alarmId>GJ_2816071613_352385154_2970760107_588354443</alarmId>
        <alarmStaId>2014070200101</alarmStaId>
   </recordInfo>
</opDetail>
根据之前在项目中配置各种解析脚本的经验,我的直觉告诉我通过xquery脚本,是可以实现这么一个转换过程,而且,之前在看《Xquery权威指南》一书时,曾看到类似的例子,于是我翻开《xquery权威指南》,根据目录提示,很快我就找到了解决办法,很简单,就是使用xquery构造元素。

使用xquery构造元素,有两种方式:直接元素构造(Direct element Construction)和计算构造(Computed Construction),下面来分别介绍:
  • 直接元素构造
这种构造方式比较简单,比较容易理解。根据书中的描述“直接构造器,使用类似XML语法,用于创建名称固定的元素和属性。”当初看这句话,并没有给予太多关注,“使用类似XML语法”我感觉这是废话,而后面“用于创建名称固定的元素和属性”这句话则直接被我忽视了。而在解决上面的问题时,我才意识到这句话的重要性。作者的意思是,直接元素构造,适合使用与节点名称和属性名称已知的元素构造,而在我们遇到的问题中,节点的名称是未知的,因此不能使用直接元素构造的方式进行。说到现在,可能大家还不知道直接元素构造是怎么一回事,举两个栗子吧。
<opDetail>
    <recordInfo>
    {
    for $a in //fieldInfo
    return <name>{$a/fieldEnName/text()}</name>
    }
    </recordInfo>
</opDetail>
在stylus-studio中针对问题中的xml串运行上面的脚本,得到如下结果:
<opDetail><recordInfo><name>alarmId</name><name>alarmStaId</name></recordInfo></opDetail>
可以看到在这里,节点opDetail,recordInfo以及name的名称都是固定的。
再比如
<opDetail>
    <recordInfo>
    {
    for $a in //fieldInfo
    return <name fieldChName="{$a/fieldChName/text()}">{$a/fieldEnName/text()}</name>
    }
    </recordInfo>
</opDetail>
在stylus-studio中针对问题中的xml串运行上面的脚本,得到如下结果:
<opDetail><recordInfo><name fieldChName="告警流水号">alarmId</name><name fieldChName="告警ID">alarmStaId</name></recordInfo></opDetail>
同理,这里的属性名称fieldChName也是固定的。
  • 计算构造
和直接元素构造不同,书中对计算构造器的描述是“允许在查询中动态生成名称。”
计算元素构造器,使用关键字element,后面跟着名称和内容。其中名称可以是字符串,也可以是用大括号括起来的名称表达式,而内容则必须是名称表达式。
语法如下:element 名称/名称表达式  内容表达式
最简单的构造方式,和上面的直接元素构造方法没什么差别,将节点的名称固定:
element html {
    element h1 { "This is a Test"}
}
运行之后,返回的结果是
<html><h1>This is a Test</h1></html>
如果针对问题中的xml串,执行下面的语句
element opDetail {
    for $a in //fieldInfo
    return element {$a/fieldEnName/text()} {$a/fieldContent/text()}
}
返回的结果是
<opDetail><alarmId>GJ_2816071613_352385154_2970760107_588354443</alarmId><alarmStaId>2014070200101</alarmStaId></opDetail>
此外,还可以这样,节点名称使用固定字符串+运算结果的方式进行,同样对问题中的xml文,执行下面的语句:
element opDetail {
    for $a in //fieldInfo
    return element {concat("ele",$a/fieldEnName/text())} {$a/fieldContent/text()}
}
返回的结果是
<opDetail><elealarmId>GJ_2816071613_352385154_2970760107_588354443</elealarmId><elealarmStaId>2014070200101</elealarmStaId></opDetail>
更多的栗子就不多介绍了,翻开《xquery权威指南》第五章,你可以找到很多栗子。

总的说来,xquery元素构造,分为直接构造和计算构造,其中直接元素构造适用于节点/属性名称不变的情况,而计算构造适用于节点/属性名称可变的情况。