2014-06-09 2 views
0

Je travaille sur une exigence où je dois retourner le nom et la valeur de l'élément en tant que paire valeur/clé en utilisant XQUERY.Renvoie le nom et la valeur de l'élément en tant que paire valeur/clé

[code = 123, px_last = attribut de valeur des premières données, attribut last_update = valeur de 2ème données et ainsi de suite]

Il y a 7 élément de données avec la valeur d'attribut à l'intérieur doit être lu comme ci-dessus avec le premier champ mappé à la première donnée et la deuxième à l'attribut de deuxième valeur de données. etc ..

Avec votre aide, j'ai pu générer la sortie mais ils nous ont frappé là où je dois cartographier le premier élément de champ pour les premières données valeur de l'attribut et ainsi de suite, etc.

Merci à l'avance

fichier 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 
() 

Sortie en ce moment:

[code = 123, données = werr, données = "qwe", données = "wer", ......,] [code = 456, data = rty, data = "tyuu", data = "uuu", ......,]

Répondre

2

Généralement, si vous pouvez décomposer votre problème en petits morceaux, cela facilitera une solution plus simple qui ressemble plus au problème lui-même.

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, ','), ']') 
+0

Merci beaucoup pour votre aide. J'ai appris une nouvelle chose aujourd'hui. –

2

Dans les parties suivantes de la réponse, je l'ai complètement ignoré la partie strip-namespace, ce qui est une mauvaise idée de toute façon. Eighter le déclare comme espace de nom par défaut et ne vous inquiétez plus, ou utilisez local-name() à la place du nom, ou utilisez l'espace de noms générique *:elementname*.


L'entrée a été modifiée lors des mises à jour de la question. Tout jusqu'à la barre horizontale suivante fait référence à la première révision de la question.

Vous pouvez faire toute la « manipulation chaîne foo » avec très peu de code en utilisant certains XQuery 3.0 caractéristiques, en particulier d'appeler des fonctions dans les étapes de l'axe et la concaténation de chaîne opérateur ||:

//idata/(      (: for all idata elements :) 
    "[" || 
    string-join((    (: combine all key/value pairs with commata :) 
    "code=" || code/data(), (: code header :) 
    data/("data=" || @value)), (: data fields :) 
    ',') || 
    ']') 

Et exactement s'inscrit dans une ligne sur Stack Overflow (si vous le voulez vraiment)!

//idata/("["||string-join(("code="||code/data(),data/("data="||@value)),',')||']') 

Avec la sortie étant

[code = 123, données = wer, données = sdf, données = zxc, données = asd, données = HGJ, données = CVB, données = bsz] [code = 345, data = ff, data = ZXD, data = wvver, data = wencvr, data = wzxcer, data = wmmer, data = wuuer]

Une version sans doute plus facile à lire avec des boucles explicites, en utilisant encore l'opérateur de concaténation (qui, à mon avis, améliore la lisibilité):

for $idata in $xml//idata 
return 
    "[" || string-join((
    "code=" || $idata/code/data(), 
    for $data in $idata/data 
    return 
     "data=" || $data/@value), 
    ',') || ']' 

Pour la question mise à jour, une seule ligne sera probablement pas trop illisible. Le code modifié à la fin se joint juste avec l'index de l'élément de données:

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), 
    ',') || ']' 
+0

Merci beaucoup. Je vais suivre votre suggestion. –

+0

J'ai été en mesure d'obtenir les données comme demandé ci-dessus et je voudrais vous remercier tous les deux, mais il se complique maintenant car l'exigence est de cartographier les champs comme ci-dessous [code = 123, px_last = abc, last_update = ... ] [code = 4656, px_last = ttr, last_update = ...] Il y a 7 éléments de données avec la valeur d'attribut insde et doivent être lus comme premier nom de champ = première valeur d'attribut de données et ainsi de suite pour les 7 champs -à-dire px_last = wer, last_update = sdf et ainsi de suite pour chaque donnée etc .. votre aide est à nouveau apprécié –

+0

S'il vous plaît poster des données représentant réellement votre problème (en éditant votre question) ainsi que les attendues d' d sortie pour cette entrée. –

Questions connexes