2012-12-24 62 views
3

我已經實現了一個使用sql和基於實體值屬性的數據庫設計的樹結構查詢機制。 我想用基於XQuery的方法看到相同功能的性能,假設可以使用XQuery來完成任務。 我的樹(XLM文件)的簡化形式如下: enter image description hereXQuery是否可以支持樹結構查詢?

有不同類型的節點,但我用在查詢的唯一屬性是節點的archetype_node_id屬性。我試圖編寫的測試查詢旨在選擇包含2個元素節點的評估節點(右側)。查詢實現需要使用所用語言的兩個關鍵能力:支持結構定義(使用布爾運算符)的能力以及定義節點屬性約束的能力(本例中爲xml屬性)。

使用XQuery,我有兩個問題 1)我似乎無法管理申報感興趣的所有節點的引用,這是我在圖 2)我不感興趣的任何節點如何返回匹配,因爲這棵樹的右邊的匹配有一個組合,而評估又有兩個元素。

這是我的第一次,天真嘗試使用FLWR:

for  $composition in doc("composition-visit.xml")//element() 
let $evaluation := (
         for $evalsneeded in $composition//element() 
         let $elementat02 := 
              (for $el02 in $evalsneeded//element() 

              where $el02/@archetype_node_id = 'at0002' 
                and exists($evalsneeded//$el02) 
              return $el02 
              ), 
          $elementat03 := 
             (for $el03 in $evalsneeded//element() 

             where $el03/@archetype_node_id = 'at0003' 
               and exists($evalsneeded//$el03) 
             return $el03 
             ) 
         where $evalsneeded/@archetype_node_id = 'openEHR-EHR-EVALUATION.goal.v1' 
           and 
            exists ($evalsneeded//$elementat02) 
            and 
            exists ($evalsneeded//$elementat03) 

         return $evalsneeded) 
where $composition/@archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'     
     and exists($composition//$evaluation) 


return $evaluation/@archetype_node_id/string(.) 

如果我介紹我的問題是我最終推動評估和元素節點的子查詢,因爲如果過濾基於它們的屬性值和位置不起作用它們是FLOWR主體中的全局變量。

當談到返回結果時我更加無能爲力,但我不想爲此提出單獨的問題。

理想情況下,當我對包含at0002和at0003代碼的元素執行AND約束時,我應該得到樹的右側,如果我對同一元素使用OR約束,我應該得到整棵樹。

這是可以用XQuery嗎?它可以作爲我在樹中尋找結構存在的測試,但我也想訪問單個節點。

更新:這是我的第二次嘗試。這實際上爲我一直在嘗試做的事打開了大門,但我不確定這是否是在XQuery中執行此操作的正確方法。我應該問另一個問題來改進這種方法嗎? :

<result> 
{ 
    for  $composition in doc("composition-visit.xml")//element() 

    where $composition/@archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'     


    return <composition> 
       <name>{$composition/name/value/string(.)}</name> 
       <evaluation>{for $eval in $composition//element() 
          let $el1 := (for $el1_in_eval in $eval//element() 
              where $el1_in_eval/@archetype_node_id = 'at0002' 
              return $el1_in_eval), 
           $el2 := (for $el2_in_eval in $eval//element() 
              where $el2_in_eval/@archetype_node_id = 'at0003' 
              return $el2_in_eval) 

            where $eval/@archetype_node_id = 'openEHR-EHR-EVALUATION.goal.v1' 
              and 
              (exists($el1) 
              and 
              exists($el2) 
              ) 
            return <eval> 
                <name>{$eval/name/value/string(.)}</name> 
                <element1>{for $element1 in $eval//element() 
                  where $element1/@archetype_node_id = 'at0002' 

                  return $element1}</element1> 
                <element2>{for $element2 in $eval//element() 
                where $element2/@archetype_node_id = 'at0003' 

                return $element2}</element2> 
              </eval> 
          }</evaluation> 
      </composition> 
} 
</result> 

基本上,我用強制讓報表的父/子關係,並用得到的回報也爲讓相應的匹配,這反過來又可以做同樣的倒樹的值。

+1

如果樹是二叉搜索樹,則使用XQuery實現該樹。看到這篇文章:http://dnovatchev.wordpress.com/2012/01/09/the-binary-search-tree-data-structurehaving-fun-with-xpath-3-0/ –

+1

這可能爲時已晚的使用......但是......看起來你正在抽象樹的頂端實現抽象樹,而抽象樹已經根據抽象樹來定義。直接使用元素樹而不是使用XML元素實現樹... – barefootliam

回答

1

它看起來像你的用例查詢「archetyped」openEHR數據。

隨意查看開源的https://github.com/LiU-IMT/EEE,它使用xQuery處理類似於您的用例的請求,但數據的建模有點不同。

它用於例如在論文http://www.ep.liu.se/ecp/070/009/ecp1270009.pdf中您可以找到一個查詢示例,該示例返回所有記錄標識,其組織檢查結果指示2006-01-01和2006-05-01之間的腫瘤病變。

在AQL(原型查詢語言)時,表示爲...

SELECT e/ehr_id/value as ehr_id 
FROM Ehr e 
CONTAINS VERSION v 
CONTAINS COMPOSITION c [openEHR-EHR-COMPOSITION.histologic_exam.v1] 
CONTAINS OBSERVATION obs [openEHR-EHR- OBSERVATION.histological_exam_result.v1] 
WHERE (EXISTS obs/data[at0001]/events[at0002]/data[at0003]/items[at0085]/items[at0033]/items[at0034] 
OR 
EXISTS obs/data[at0001]/events[at0002]/data[at0003]/items[at0085]/items[at0033]/items[at0035]) 
AND c/context/start_time/value >= '2006-01-01T00:00:00,000+01:00' 
AND c/context/start_time/value < '2006-05-01T00:00:00,000+01:00'` 

...這看起來像這樣的時候自動解析和轉換爲XQuery的:

declare namespace v1 = "http://schemas.openehr.org/v1"; 
declare default element namespace "http://schemas.openehr.org/v1"; 
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance"; 
declare namespace eee = "http://www.imt.liu.se/mi/ehr/2010/EEE-v1.xsd"; 
declare namespace res = "http://www.imt.liu.se/mi/ehr/2010/xml-result-v1#"; 
<res:xml-results> 
<res:head><res:variable name="ehr_id"/></res:head> 
<res:results> 
{let $ehrRoot := //eee:EHR 
    for $e in $ehrRoot 
    for $v in $e/eee:versioned_objects/eee:versions 
    for $c in $v//*[@xsi:type='v1:COMPOSITION' and @archetype_node_id="openEHR-EHR-COMPOSITION.histologic_exam.v1"] 
    for $obs in $c//*[@xsi:type='v1:OBSERVATION' and @archetype_node_id= "openEHR-EHR-OBSERVATION.histological_exam_result.v1"] 
    where 
    (
    exists($obs/data[@archetype_node_id = 'at0001']/events[@archetype_node_id = 'at0002']/data[@archetype_node_id='at0003']/items[@archetype_node_id = 'at0085']/items[@archetype_node_id = 'at0033']/items[@archetype_node_id = 'at0034']) 
    or 
    exists($obs/data[@archetype_node_id = 'at0001']/events[@archetype_node_ id = 'at0002']/data[@archetype_node_id = 'at0003']/items[@archetype_node_id = 'at0085']/items[@archetype_node_id = 'at0033']/items[@archetype_node_id = 'at0035']) 
    ) 
    and 
    $c/context/start_time/value >= '2006-01-01T00:00:00,000+01:00' 
    and 
    $c/context/start_time/value < '2006-05-01T00:00:00,000+01:00' 
return 
<res:result><res:binding name="ehr_id">{$e/eee:ehr_id/value}</res:binding></res:result>} 
</res:results> 
</res:xml-results> 

這種模式可能值得在你的用例中嘗試。有關解決方案和上下文的更多詳細信息,請參見http://www.biomedcentral.com/1472-6947/13/57