我正在处理一个需求,我需要使用XQUERY将元素名称和值作为键值对返回,如下所示。
[code = 123,px_last =第一个数据的value属性,last_update =第二个数据的value属性,依此类推]
内部属性值有7个数据元素应如上所述读取,第一个字段映射到第一个数据,第二个字段映射到第二个数据值属性。 等。
在你的帮助下,我能够生成输出,但是我需要将第一个字段元素映射到第一个数据属性值等等。
提前致谢
XML文件:
<root>
<fields>
<field>PX_LAST</field>
<field>LAST_UPDATE</field>
<field>LAST_UPDATE_DT</field>
<field>SECURITY_DES</field>
<field>FUT_CUR_GEN_TICKER</field>
<field>YLD_CNV_BID</field>
<field>YLD_CNV_ASK</field>
</fields>
<Datas>
<Data>
<code>0</code>
<ins>
<id>CT30</id>
<key>Govt</key>
<ins/>
<data value="98.843750"/>
<data value="16:14:45">
</data>
<data value="06/03/2014"/>
<data value="T 3 3/8 05/15/44"/>
<data value=""/>
<data value="3.439"/>
<data value="3.437"/>
</Data>
<Data>
<code>0</code>
<ins>
<id>US0001W</id>
<key>Index</key>
<ins/>
<data value=".119000"/>
<data value="06:46"/>
<data value="06/03/2014"/>
<data value="ICE LIBOR USD 1 Week"/>
<data value=""/>
<data value="N.A."/>
<datavalue=".11900"></data>
</Data>
</Datas>
</root>
的XQuery:
declare function xf:strip-namespace($e as element())
as element()
{
element { xs:QName(local-name($e)) }
{
for $child in $e/(@*,node())
return
if ($child instance of element())
then
xf:strip-namespace($child)
else
$child
}
};
let $nl := " "
let $count := 0
for $x in doc("test.xml")/soap:Envelope/soap:Body/dlws:retrieveGetDataResponse/dlws:instrumentDatas//*
let $y:=xf:strip-namespace($x)
return
if($y/name() = 'instrumentData')
then
concat($nl,'[','')
else if($y/name()='data')
then
concat($y/name(),'=',$y/data(@value),',')
else if($y/name() != 'instrument')
then
concat($y/name(),'=',$y/text(),',')
else
()
立即输出:
[代码= 123,数据= WERR,数据=&#34; QWE&#34;,数据=&#34; WER&#34;,......,] [代码= 456,数据= RTY,数据=&#34; tyuu&#34;,数据=&#34; UUU&#34;,......,]
答案 0 :(得分:2)
通常情况下,如果您可以将问题分解成更小的部分,它将有助于实现更接近问题本身的更简单的解决方案。
declare function local:make-pair(
$e as element()
) as xs:string?
{
typeswitch($e)
case element(data) return concat(local-name($e), '=', $e/@value)
default return concat(local-name($e), '=', $e)
};
let $idatas :=
<idatas>
<idata>
<code>123</code>
<data value="wer"></data>
<data value="sdf"></data>
<data value="zxc"></data>
<data value="asd"></data>
<data value="jgh"></data>
<data value="cvb"></data>
<data value="bsz"></data>
</idata>
<idata>
<code>345</code>
<data value="ff"></data>
<data value="zxd"></data>
<data value="wvver"></data>
<data value="wencvr"></data>
<data value="wzxcer"></data>
<data value="wmmer"></data>
<data value="wuuer"></data>
</idata>
</idatas>
for $idata in $idatas/idata
let $pairs :=
for $p in $idata/*
return local:make-pair($p)
return concat('[', string-join($pairs, ','), ']')
答案 1 :(得分:2)
在答案的以下部分,我完全忽略了strip-namespace
部分,这无论如何都是个坏主意。 Eighter将其声明为默认命名空间,不再担心它,或使用local-name()
而不是名称,或使用通配符命名空间mather *:elementname*
。
在更新问题期间修改了输入。到下一个水平条的所有内容都是指问题的第一个修订版。
使用一些XQuery 3.0功能,您可以使用极少数代码执行所有“字符串操作foo”,特别是在轴步骤中调用函数和字符串连接运算符||
:
//idata/( (: for all idata elements :)
"[" ||
string-join(( (: combine all key/value pairs with commata :)
"code=" || code/data(), (: code header :)
data/("data=" || @value)), (: data fields :)
',') ||
']')
它完全适合Stack Overflow上的一行(如果你真的想要的话)!
//idata/("["||string-join(("code="||code/data(),data/("data="||@value)),',')||']')
输出为
[code = 123,data = wer,data = sdf,data = zxc,data = asd,data = jgh,data = cvb,data = bsz] [code = 345,data = ff,data = zxd,data = wvver,数据= wencvr,数据= wzxcer,数据= wmmer,数据= wuuer]
一个可能更具可读性的版本,带有显式循环,仍然使用连接运算符(在我看来增强了可读性):
for $idata in $xml//idata
return
"[" || string-join((
"code=" || $idata/code/data(),
for $data in $idata/data
return
"data=" || $data/@value),
',') || ']'
对于更新的问题,单行可能会变得太难以理解。最后修改的代码只是与数据元素的索引连接:
for $dataset in /root/Datas/Data
return
"[" || string-join((
"code=" || $dataset/code/data(),
for $data at $position in $dataset/data
let $field := /root/fields/field[$position]
return
$field || "=" || $data/@value),
',') || ']'