【问题标题】:Oracle extract few xpath valuesOracle 提取几个 xpath 值
【发布时间】:2022-01-22 06:45:17
【问题描述】:

我正在尝试从此 xml 中提取三个打印机位置
打印机位置存储在打印机/打印机头/元素下,属性名称为打印机位置

问题是如何在列表中获取结果 像“美国,英国,(空)”
或者像我可以这样查询的列格式:

select * from ( this xml query) where column1 = "USA"

这是一个示例 xml:

    <?xml version="1.0" encoding="UTF16" standalone="no" ?>
    <printer>
        <printer-header>
            <elem name="printerId">XROX101-19341</elem>
            <elem name="printerDate">05/11/19 12:27:48</elem>
            <elem name="printerLocations">
                <elem name="countryCd">USA</elem>
            </elem>
            <elem name="printerLocations">
                <elem name="countryCd">UK</elem>
            </elem>
            <elem name="printerLocations">
                <elem name="countryCd"/>
            </elem>
        </printer-header>
    </printer>

我尝试了什么:

select  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"]/elem[@name="countryCd"]/text()').getStringVal()   from printers 

/

这只是美国的一个刺痛价值

我希望得到的输出是一个包含三列的表格,

COUNTRY1     COUNTRY2     COUNTRY3
USA          UK           NULL

【问题讨论】:

  • “这是……”究竟是什么?

标签: xml oracle extract


【解决方案1】:

您可以使用 XMLTable 提取多个值,包括父元素值,例如:

select printerId, printerDate, countryCd
from xmltable(
  '/printer/printer-header/elem[@name="printerLocations"]'
  passing xmltype('<?xml version="1.0" encoding="UTF16" standalone="no" ?>
<printer>
    <printer-header>
        <elem name="printerId">XROX101-19341</elem>
        <elem name="printerDate">05/11/19 12:27:48</elem>
        <elem name="printerLocations">
            <elem name="countryCd">USA</elem>
        </elem>
        <elem name="printerLocations">
            <elem name="countryCd">UK</elem>
        </elem>
        <elem name="printerLocations">
            <elem name="countryCd"/>
        </elem>
    </printer-header>
</printer>')
  columns
    printerId varchar2(30) path './../elem[@name="printerId"]',
    printerDate varchar2(17) path './../elem[@name="printerDate"]',
    countryCd varchar2(3) path 'elem[@name="countryCd"]'
)
PRINTERID PRINTERDATE COUNTRYCD
XROX101-19341 05/11/19 12:27:48 USA
XROX101-19341 05/11/19 12:27:48 UK
XROX101-19341 05/11/19 12:27:48 null

假设它是固定格式,您可以将“printDate”值转换为实际日期。

无论哪种方式,您都可以将其用作内联视图或 CTE。

db<>fiddle

我尝试了什么: 从打印机中选择 XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"]/elem[@name="countryCd"]/text()').getStringVal()

这会将所有国家/地区值作为单个字符串获取;使用 XMLTable 代替分别获取每个值,并允许您轻松获取其他数据,以及一次获取多个 XML 文档的数据。

由于您的字符串来自表格,因此变为:

select x.printerId, x.printerDate, x.countryCd
from printers p
cross apply xmltable(
  '/printer/printer-header/elem[@name="printerLocations"]'
  passing xmltype(p.xml_string)
  columns
    printerId varchar2(30) path './../elem[@name="printerId"]',
    printerDate varchar2(17) path './../elem[@name="printerDate"]',
    countryCd varchar2(3) path 'elem[@name="countryCd"]'
) x
PRINTERID PRINTERDATE COUNTRYCD
XROX101-19341 05/11/19 12:27:48 USA
XROX101-19341 05/11/19 12:27:48 UK
XROX101-19341 05/11/19 12:27:48 null

它包含在外部查询中,转换后的日期为:

select * from (
  select
    printerId,
    to_date(printerDate, 'DD/MM/RR HH24:MI:SS') as printerDate,
    countryCd
  from printers p
  cross apply xmltable(
    '/printer/printer-header/elem[@name="printerLocations"]'
    passing xmltype(p.xml_string)
    columns
      printerId varchar2(30) path './../elem[@name="printerId"]',
      printerDate varchar2(17) path './../elem[@name="printerDate"]',
      countryCd varchar2(3) path 'elem[@name="countryCd"]'
  )
) x
where x.countryCd = 'USA'
PRINTERID PRINTERDATE COUNTRYCD
XROX101-19341 2019-11-05 12:27:48 USA

db<>fiddle


我只需要一张三列表格

您可以调整该结果;但更简单地说,您可以使用类似的方法,按索引定位每个打印机位置:

select x.countryCd1, x.countryCd2, x.countryCd3
from printers p
cross apply xmltable(
  '/printer/printer-header'
  passing xmltype(p.xml_string)
  columns
    countryCd1 varchar2(3) path 'elem[@name="printerLocations"][1]/elem[@name="countryCd"]',
    countryCd2 varchar2(3) path 'elem[@name="printerLocations"][2]/elem[@name="countryCd"]',
    countryCd3 varchar2(3) path 'elem[@name="printerLocations"][3]/elem[@name="countryCd"]'
) x
COUNTRYCD1 COUNTRYCD2 COUNTRYCD3
USA UK null

db<>fiddle

您可以改为使用三个 XMLQuery 调用,但这会涉及更多重复。

或者,如果您真的愿意,您仍然可以使用您的原始摘录 3 次,并添加一个索引:

select
  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][1]/elem[@name="countryCd"]/text()').getStringVal() as countryCd1,
  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][2]/elem[@name="countryCd"]/text()').getStringVal() as countryCd2,
  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][3]/elem[@name="countryCd"]/text()').getStringVal() as countryCd3
from printers

...gets the same result.

无论哪种方式,您都必须提前知道最终结果中有多少值(列)。 (否则你必须使用动态SQL...)

【讨论】:

  • 非常感谢您的详细回答,并为您的困惑感到抱歉……但我不需要其余的东西,我只需要一张包含三列的表格,COUNTRY1。国家2。国家 3。 (美国、英国、NULL))
  • @JavaSheriff - 你知道总会有三个值(或最多三个,但不会更多)吗?
  • 希望如此,其余的我可以忽略 :)
  • @JavaSheriff - 好的,添加了如何做到这一点。希望这是有道理的。
  • 是的!非常感谢!那种答案让我感谢stackoverflow!谢谢!
猜你喜欢
  • 1970-01-01
  • 2020-01-11
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多