'How to return values in xml with different xpath

I am trying to parse xml in my oracle DB to return individual rows. I have different xpath the ,downPaymentSourceType INT PATH '/downPaymentSource/downPaymentSourceTypeDd' and ,DownpaymentAmount INT PATH '/downPaymentSource/amount' are returning nulls. How do I handle this to provide accurate results. Thanks

    WITH t( xml ) AS
        (
        SELECT XMLType('<loanApplication xmlns="http://www.abcdef.com/Schema/FCX/1" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <deal>
            <applicationDate>2017-01-10T16:15:00-05:00</applicationDate>
            <applicationId>QA-8899</applicationId>
            <combinedGds>0.13055</combinedGds>
            <combinedLtv>1.8</combinedLtv>
            <combinedTds>10.2714</combinedTds>
            <dealPurposeDd>2</dealPurposeDd>
            <dealTypeDd>0</dealTypeDd>
            <downPaymentSource>
              <amount>25000.0</amount>
              <downPaymentSourceTypeDd>1</downPaymentSourceTypeDd>
              <description>aasdadsf</description>
            </downPaymentSource>
            <downPaymentSource>
              <amount>25000.0</amount>
              <downPaymentSourceTypeDd>6</downPaymentSourceTypeDd>
              <description>wrewertwerewrt</description>
            </downPaymentSource>
            <downPaymentSource>
              <amount>50000.0</amount>
              <downPaymentSourceTypeDd>10</downPaymentSourceTypeDd>
              <description>second and thirs</description>
            </downPaymentSource>
            <estimatedClosingDate>2017-12-05T00:00:00-05:00</estimatedClosingDate>
            <financingWaiverDate>2017-01-04T00:00:00-05:00</financingWaiverDate>
            <refiImprovementAmount>10000.0</refiImprovementAmount>
            <refiImprovementsDesc>roof</refiImprovementsDesc>
            <refiImprovementsFlag>Y</refiImprovementsFlag>
            <refiPurpose>refi purpose</refiPurpose>
            <taxPayorDd>1</taxPayorDd>
            <additionalData dataType="String" name="firmLicenseRegistrationNumber" xmlns:t="http://www.abcdef.com/Schema/FCX/1">C000312345</additionalData>
          </deal>
<applicantGroup>
    <applicantGroupTypeDd>0</applicantGroupTypeDd>
    <applicant>
      <employmentHistory>
        <employerName>employer name</employerName>
        <employmentHistoryStatusDd>0</employmentHistoryStatusDd>
        <employmentHistoryTypeDd>0</employmentHistoryTypeDd>
        <income>
          <annualIncomeAmount>200000.0</annualIncomeAmount>
          <incomeAmount>200000.0</incomeAmount>
          <incomePeriodDd>0</incomePeriodDd>
          <incomeTypeDd>6</incomeTypeDd>
        </income>
      </employmentHistory>
      <asset>
        <assetDescription>qwerqwer</assetDescription>
        <assetTypeDd>0</assetTypeDd>
        <assetValue>1111.0</assetValue>
      </asset>
      <liability>
        <broker>
          <creditLimit>9283.0</creditLimit>
          <liabilityAmount>9999999.8</liabilityAmount>
          <liabilityMonthlyPayment>299999.99</liabilityMonthlyPayment>
          <liabilityTypeDd>2</liabilityTypeDd>
        </broker>
      </liability>
    </applicant>
    <applicant>
      <employmentHistory>
        <income>
          <annualIncomeAmount>150000.0</annualIncomeAmount>
          <incomeAmount>150000.0</incomeAmount>
          <incomeDescription>income description</incomeDescription>
          <incomePeriodDd>0</incomePeriodDd>
          <incomeTypeDd>6</incomeTypeDd>
        </income>
      </employmentHistory>
    </applicant>
  </applicantGroup>
        </loanApplication>')
         FROM dual
        )
        SELECT 
        JSON_OBJECT (
            KEY 'dealClosingDate' value x.DealClosingDate   
            ,KEY 'dealPurpose' value x.dealPurpose
            ,KEY 'combinedGds' value x.combinedGds
            ,KEY 'combinedTds' value x.combinedTds
            ,KEY 'combinedLtv' value x.combinedLtv
            ,KEY 'downpaymentAmount' value x.DownpaymentAmount      
            ,KEY 'combinedAssets' value y.CombinedAssets
            ,KEY 'combinedLiabilities' value y.CombinedLiabilities
            ,KEY 'combinedIncome' value y.CombinedIncome
            ,KEY 'downPaymentSourceType' value x.downPaymentSourceType
            ,KEY 'sourceAmount' value x.DownpaymentAmount
            ) Deal
    FROM t,
    XMLTABLE(XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/loanApplication/deal'
          PASSING xml
          COLUMNS 
                 DealClosingDate timestamp with time zone PATH 'estimatedClosingDate'
                 ,dealPurpose  INT PATH 'dealPurposeDd'
                 ,combinedGds  INT PATH 'combinedGds'
                 ,combinedTds  INT PATH 'combinedTds'
                 ,combinedLtv  INT PATH 'combinedLtv'
                 ,downPaymentSourceType INT PATH '/downPaymentSource/downPaymentSourceTypeDd'
                ,DownpaymentAmount  INT PATH '/downPaymentSource/amount'
             ) x,
         XMLTABLE(XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/loanApplication/applicantGroup/applicant'
          PASSING xml
          COLUMNS 
            CombinedLiabilities  INT PATH 'liability/broker/liabilityAmount'
            ,CombinedIncome  INT PATH 'employmentHistory/income/incomeAmount'
            ,CombinedAssets INT PATH 'asset/assetValue'
            ) y


Solution 1:[1]

You are cross-joining the base table and the two XMLTable calls. Your second XMLTable looks for applicantGroup nodes, and there aren't any in this XML document, so that gets now rows; and therefore the query overall returns no rows either.

If you change the second (implicit) cross join to outer apply then you'll still see the data found by the first XMLtable. It's unclear if there will always be a deal node, but you can make the first join an outer apply too.

...
FROM t
OUTER APPLY
    XMLTABLE(XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/loanApplication/deal'
      PASSING xml
      COLUMNS 
             DealClosingDate timestamp with time zone PATH 'estimatedClosingDate'
             ,dealPurpose  INT PATH 'dealPurposeDd'
             ,combinedGds  INT PATH 'combinedGds'
             ,combinedTds  INT PATH 'combinedTds'
             ,combinedLtv  INT PATH 'combinedLtv'
             ,downPaymentSourceType INT PATH '/downPaymentSource/downPaymentSourceTypeDd'
            ,DownpaymentAmount  INT PATH '/downPaymentSource/amount'
         ) x
OUTER APPLY
    XMLTABLE(XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/loanApplication/applicantGroup/applicant'
      PASSING xml
      COLUMNS 
        CombinedLiabilities  INT PATH 'liability/broker/liabilityAmount'
        ,CombinedIncome  INT PATH 'employmentHistory/income/incomeAmount'
        ,CombinedAssets INT PATH 'asset/assetValue'
        ) y
DEAL
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":null,"combinedAssets":null,"combinedLiabilities":null,"combinedIncome":null,"downPaymentSourceType":null,"sourceAmount":null}

db<>fiddle

(I changed the dealClosingDate data type because... well, I could, and it didn't really look right as a string; but as it ends up as a string in the JSON anyway it's a bit moot.)

Depending on whether you can have multiple (or zero) deal nodes and/or multiple (or zero) applicantGroup nodes - presumably groups can have multiple child nodes - you might be able to structure the XMLTables a bit differently, but it depends on the data and what you want to see.


from your result, you can see that downPaymentSourceType and downpaymentAmount are retuning nulls which is not the case in the XML

That's because the path you are using for those starts with /downPaymentSource/... which doesn't exist within the XPath; and if you did ./downPaymentSource/... or just /downPaymentSource/... you would get a "expected singleton sequence - got multi-item sequence" error.

You can extract the collection of those downPaymentSource nodes as an XMLType, and then use another XMLTable to expand those too:

FROM t
OUTER APPLY
    XMLTABLE(XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/loanApplication/deal'
      PASSING xml
      COLUMNS 
             DealClosingDate timestamp with time zone PATH 'estimatedClosingDate'
             ,dealPurpose  INT PATH 'dealPurposeDd'
             ,combinedGds  INT PATH 'combinedGds'
             ,combinedTds  INT PATH 'combinedTds'
             ,combinedLtv  INT PATH 'combinedLtv'
             ,downPayments XMLType PATH 'downPaymentSource'
--             ,downPaymentSourceType INT PATH '/downPaymentSource/downPaymentSourceTypeDd'
--            ,DownpaymentAmount  INT PATH '/downPaymentSource/amount'
         ) x
OUTER APPLY
    XMLTABLE(
      XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/downPaymentSource'
      PASSING x.downPayments
      COLUMNS
             downPaymentSourceType INT PATH 'downPaymentSourceTypeDd'
            ,DownpaymentAmount  INT PATH 'amount'
        ) y
OUTER APPLY
    XMLTABLE(XMLNAMESPACES(DEFAULT 'http://www.abcdef.com/Schema/FCX/1'), '/loanApplication/applicantGroup/applicant'
      PASSING xml
      COLUMNS 
        CombinedLiabilities  INT PATH 'liability/broker/liabilityAmount'
        ,CombinedIncome  INT PATH 'employmentHistory/income/incomeAmount'
        ,CombinedAssets INT PATH 'asset/assetValue'
        ) z
DEAL
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":25000,"combinedAssets":1111,"combinedLiabilities":10000000,"combinedIncome":200000,"downPaymentSourceType":1,"sourceAmount":25000}
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":25000,"combinedAssets":null,"combinedLiabilities":null,"combinedIncome":150000,"downPaymentSourceType":1,"sourceAmount":25000}
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":25000,"combinedAssets":1111,"combinedLiabilities":10000000,"combinedIncome":200000,"downPaymentSourceType":6,"sourceAmount":25000}
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":25000,"combinedAssets":null,"combinedLiabilities":null,"combinedIncome":150000,"downPaymentSourceType":6,"sourceAmount":25000}
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":50000,"combinedAssets":1111,"combinedLiabilities":10000000,"combinedIncome":200000,"downPaymentSourceType":10,"sourceAmount":50000}
{"dealClosingDate":"2017-12-05T00:00:00.000000-05:00","dealPurpose":2,"combinedGds":0,"combinedTds":10,"combinedLtv":2,"downpaymentAmount":50000,"combinedAssets":null,"combinedLiabilities":null,"combinedIncome":150000,"downPaymentSourceType":10,"sourceAmount":50000}

db<>fiddle

That still might not be what you want though; you might be trying to get a JSON array of those values, and maybe of the applicants too - depends if you're expecting 1, 2, or 6 JSON docs from this example XML doc. However, if you do want different JSON and can't figure out how to get there then you would need to ask a new question about that.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1