将元素名称和值作为键值对返回

时间:2014-06-09 20:55:40

标签: xquery xquery-3.0

我正在处理一个需求,我需要使用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 := "&#10;"

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;,......,]

2 个答案:

答案 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),
  ',') || ']'