【问题标题】:How to parse xml with optional elements如何使用可选元素解析 xml
【发布时间】:2016-08-11 06:25:51
【问题描述】:

SEPA ISO XML 事务文件需要在 ASP:NET 4.6 MVC 控制器中的 Postgres 9.1+ 中解析为平面表。

我尝试了下面的代码,但这会产生错误的结果:

endaaa            tasusumma  orderinr
XX00221059842412     150.00  PV04131
XX00221059842412       0.38  PV04131

由于第二行没有 EndToEnd,因此第二行 orderinr 列中应该有 null 或空文本:

endaaa            tasusumma  orderinr
XX00221059842412     150.00  PV04131
XX00221059842412       0.38  null

如何解决这个问题?

解析可以通过其他方式完成,例如如果这更合理,则使用 xslt 样式表进行转换或在客户端 ASP.NET 4.6 MVC 中。

create temp table t(x xml, nsa text[][]) on commit drop;
insert into t values(
'<?xml version=''1.0'' encoding=''UTF-8''?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
  <BkToCstmrStmt>
    <Stmt>
      <Acct>
        <Id>
          <IBAN>XX00221059842412</IBAN>
        </Id>
      </Acct>
      <Ntry>
        <Amt Ccy="EUR">150.00</Amt>
        <NtryDtls>
          <TxDtls>
            <Refs>
              <EndToEndId>PV04131</EndToEndId>
            </Refs>
          </TxDtls>
        </NtryDtls>
      </Ntry>
      <Ntry>
        <Amt Ccy="EUR">0.38</Amt>
        <NtryDtls>
          <TxDtls>
            <Refs>
              <AcctSvcrRef>2016080100178214-2</AcctSvcrRef>
            </Refs>
          </TxDtls>
        </NtryDtls>
      </Ntry>
    </Stmt>
  </BkToCstmrStmt>
</Document>
', ARRAY[ARRAY['ns','urn:iso:std:iso:20022:tech:xsd:camt.053.001.02']]);

SELECT 
unnest(xpath('/ns:Document/ns:BkToCstmrStmt/ns:Stmt/ns:Acct/ns:Id/ns:IBAN/text()', x,nsa))::text AS endaaa,
unnest(xpath('/ns:Document/ns:BkToCstmrStmt/ns:Stmt/ns:Ntry/ns:Amt/text()', x,nsa))::text::numeric AS tasusumma
 , unnest(xpath('/ns:Document/ns:BkToCstmrStmt/ns:Stmt/ns:Ntry/ns:NtryDtls/ns:TxDtls/ns:Refs/ns:EndToEndId/text()', x,nsa))::text AS orderinr
FROM t;

更新

使用 Hannes 答案中的代码在 Postgres 9.1 中返回空行如何使其在 9.1 中工作?

也发布在 pgsql.general 邮件列表中。

【问题讨论】:

    标签: c# xml postgresql xslt postgresql-9.1


    【解决方案1】:

    你需要先提取所有的ns:Ntry元素,然后获取每个元素的数量和EndToEndId:

    SELECT 
        endaaa,
        (xpath('ns:Amt/text()', x,nsa))[1]::text::numeric AS tasusumma,
        (xpath('ns:NtryDtls/ns:TxDtls/ns:Refs/ns:EndToEndId/text()', x,nsa))[1] AS orderinr
    
    FROM (
        SELECT (xpath('/ns:Document/ns:BkToCstmrStmt/ns:Stmt/ns:Acct/ns:Id/ns:IBAN/text()', x,nsa))[1] as endaaa,
        unnest(xpath('/ns:Document/ns:BkToCstmrStmt/ns:Stmt/ns:Ntry', x,nsa)) as x, nsa
        FROM t
    ) Ntry
    

    【讨论】:

    • 在 9.1 中它返回两个空行。如何使它在"PostgreSQL 9.1.2 on x86_64-unknown-linux-gnu, compiled by gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit" 中工作?在 9.5 中它可以工作。
    • 我已验证该查询在“x86_64-unknown-linux-gnu 上的 PostgreSQL 9.1.23,由 gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2,64 位编译” .看来您必须至少升级到 9.1.15 才能修复 xpath() 命名空间处理错误。
    • 谢谢。如何将 IBAN 列添加到结果表中?它对所有行具有相同的值。我用新的测试用例修改了问题。如何获得恩达?结果集中的列。服务器在不受支持的 Debian Squeeze 中运行。不知道如何升级。
    • 答案已更新以包括 IBAN。这只有在 XML 中只有一个“ns:Stmt”条目时才有效!否则,您将不得不构建第三个查询级别,首先选择 ns:Stmt 条目,然后从中选择 IBAN 和 Ntry,第三个数量和 EndToEndId。
    • 关于升级,请查看postgresql.org/download/linux/debian 获取有关如何使用 PostgreSQL APT 存储库的说明。我不是真正的 Debian 专家,但据我所知,Squeezy 也应该有 9.1.23。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多