在postgres中使用xpath提取多级xml数据

Sco*_*ood 2 xml postgresql xpath

我需要从 postgres 中的 xml 列中提取三列数据,以便将 xml 扩展为适当的列。其中一列需要是 xml 的一个嵌套级别的属性,其他列是下一级嵌套的属性。应重复上级的数据。这可能吗?具体内容请参见下面的示例。

谢谢,--sw

考虑以下查询:

with x as (select
'<catalog catalog-id="manufacturer-catalog-id">
    <category-assignment category-id="category1" product-id="product1"/>
    <category-assignment category-id="category1" product-id="product2"/>
    <category-assignment category-id="category2" product-id="product3"/>
</catalog>'::xml as t
)
(
select 
    xpath('/catalog/@catalog-id', catalog_xml) catalog_id,  
    xpath('//@category-id', catalog_xml) category_assignment_category_id,
    xpath('//@product-id', catalog_xml) category_assignment_product_id
from (select unnest(xpath('/catalog', t)) catalog_xml from x) q
) 
Run Code Online (Sandbox Code Playgroud)

此查询返回以下数据:

"{manufacturer-catalog-id}";"{category1,category1,category2}";"{product1,product2,product3}"
Run Code Online (Sandbox Code Playgroud)

这个查询:

with x as (select
'<catalog catalog-id="manufacturer-catalog-id">
    <category-assignment category-id="category1" product-id="product1"/>
    <category-assignment category-id="category1" product-id="product2"/>
    <category-assignment category-id="category2" product-id="product3"/>
</catalog>'::xml as t
)
(
select
    xpath('/catalog/@catalog-id', catalog_xml) catalog_id,  
    xpath('//@category-id', catalog_xml) category_assignment_category_id,
    xpath('//@product-id', catalog_xml) category_assignment_product_id
from (select unnest(xpath('/catalog/category-assignment', t)) catalog_xml from x) q
) 
Run Code Online (Sandbox Code Playgroud)

---编辑---

返回此数据:

"{}";"{category1}";"{product1}"
"{}";"{category1}";"{product2}"
"{}";"{category2}";"{product3}"
Run Code Online (Sandbox Code Playgroud)

我需要这些数据:

"{manufacturer-catalog-id}";"{category1}";"{product1}"
"{manufacturer-catalog-id}";"{category1}";"{product2}"
"{manufacturer-catalog-id}";"{category2}";"{product3}"
Run Code Online (Sandbox Code Playgroud)

Daz*_*zed 5

我很高兴这个问题已经有几年了,但我带着类似的问题来到这里,并相信我找到了答案。

with x as (select
'<catalog catalog-id="manufacturer-catalog-id">
    <category-assignment category-id="category1" product-id="product1"/>
    <category-assignment category-id="category1" product-id="product2"/>
    <category-assignment category-id="category2" product-id="product3"/>
</catalog>'::xml as t
)
(
select 
       xpath('/catalog/@catalog-id', cat_node) catalog_id,
       xpath('/category-assignment/@category-id', cat_assn_list) category_id,
       xpath('/category-assignment/@product-id', cat_assn_list) product_id         
 from (select unnest(xpath('/catalog/category-assignment', t)) cat_assn_list, t cat_node from x) q
);
Run Code Online (Sandbox Code Playgroud)

这给出了

        catalog_id         | category_id | product_id
---------------------------+-------------+------------
 {manufacturer-catalog-id} | {category1} | {product1}
 {manufacturer-catalog-id} | {category1} | {product2}
 {manufacturer-catalog-id} | {category2} | {product3}
(3 rows)
Run Code Online (Sandbox Code Playgroud)

这基本上执行返回两列的基本选择:1)用于获取分配列表(多行)的 xpath 和 2)原始类别节点。然后,返回的行由更高级别的 xpath 语句处理 - 来自完整类别节点列的类别 ID 和进入分配列表项的列级别 xpath。

我相信OP的问题是,纯粹从单个分配列表列中驱动这意味着,由于postgres在适当的级别返回xml节点集,而不是指向单个dom的指针,因此返回的xml输出低于目录级别,并且xml ndoeset 不能向上遍历,例如使用“ancestor::”。

希望这对其他人有帮助。

编辑 - 我无法评论其性能,因为我相信同一目录节点中的每个分配行都会重复目录 ID xpath。