Aprecio que esta pergunta tenha alguns anos, mas vim aqui com um problema semelhante e acredito que encontrei uma resposta.
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
);
Isto dá
catalog_id | category_id | product_id
---------------------------+-------------+------------
{manufacturer-catalog-id} | {category1} | {product1}
{manufacturer-catalog-id} | {category1} | {product2}
{manufacturer-catalog-id} | {category2} | {product3}
(3 rows)
Isso basicamente executa a seleção de base que retorna duas colunas 1) um xpath para obter a lista de atribuição (várias linhas) e 2) o nó de categoria original. As linhas retornadas são então trabalhadas pelas instruções xpath de nível superior - o category-id da coluna do nó de categoria completo e os xpaths de nível de coluna para o item da lista de atribuição.
Acredito que o problema do OP foi que direcionar isso puramente para fora da coluna da lista de atribuição única significa que, como o postgres está retornando conjuntos de nós xml no nível apropriado, em vez de ponteiros para um único dom, a saída xml retornada por isso está abaixo do nível do catálogo e esse xml ndoeset não pode ser percorrido para cima, por exemplo. com "ancestral::".
Espero que isso ajude alguém.
Editar - não posso comentar sobre o desempenho disso, pois acredito que o xpath do catalog-id será repetido para cada linha de atribuição no mesmo nó do catálogo.