XMLTYPE ORA-31011: XML parsing failed without root element only nested elements

1.2k Views Asked by At

I have a function in oracle that return a XMLType, but without root element because the root element can repeat, and I need that to use in another select with XMLElements

My function is:

    CREATE OR REPLACE FUNCTION F_XML_WITHOUT_ROOT 
    RETURN XMLTYPE AS 
      
      vXML CLOB;
      vXML_TEMP CLOB;
      
    BEGIN
      vXML := '';
    
      FOR cI IN (
        SELECT
          '10' ALM_IN_CODIGO,
          '1' LOC_IN_CODIGO,
          'DE' NAT_ST_CODIGO
        FROM DUAL
        UNION ALL
        SELECT
          '10' ALM_IN_CODIGO,
          '2' LOC_IN_CODIGO,
          'DE' NAT_ST_CODIGO
        FROM DUAL
      ) LOOP
      
        SELECT
          (
            XMLSerialize(content
              XMLElement("Item" 
                , XMLForest(
                    cI.ALM_IN_CODIGO AS ALM
                  , cI.LOC_IN_CODIGO AS LOC
                  , cI.NAT_ST_CODIGO AS NAT
                ) Item
              ).extract('/*') indent
            ) 
          ) XML_BL_XML
          INTO vXML_TEMP
          FROM DUAL;
        
        vXML := vXML || vXML_TEMP;
        
      END LOOP;
      
      RETURN XMLTYPE.CreateXML(vXML);
    END F_XML_WITHOUT_ROOT;

When I called that:

    SELECT
    MGCLI.F_XML_WITHOUT_ROOT()
    FROM DUAL;

I received the error code

ORA-31011: XML parsing failed

I think that's have a better way to make this work, but I don't know how

    <Item><ALM>10</ALM><LOC>1</LOC><NAT>DE</NAT></Item>
    <Item><ALM>10</ALM><LOC>2</LOC><NAT>DE</NAT></Item>

The right function is called in this select to make the entire XML

     SELECT
     XMLSerialize(content
        XMLElement("Group", XMLAttributes('I' AS "OP")
        , XMLForest(
              3 FIL
            , 59 TPD
        ) 
        , XMLElement("Obs"
            , XMLForest(
              'N' OB_CH_TYPE
              , (
                'Ref. '
              ) OB_ST_OBS
            )
          )
          , (
            SELECT
              XMLAgg(
                XMLElement("Item", XMLAttributes('I' AS "OP")
                  , XMLElement("ITN",1)
                  , MGCLI.F_XML_WITHOUT_ROOT()
                )
              ) FROM DUAL
            )       
          ).extract('/*') indent
        ) XML_BL_XML
            FROM DUAL
            ;
2

There are 2 best solutions below

5
On

XML documents must have a single root element, else they are not well-formed, and compliant XML parsers are required to report such a problem as an error.

Fix your XML by wrapping the multiple elements in a single root element.

0
On

I get one way to make what i want:

I change the function:

create or replace FUNCTION F_XML_WITHOUT_ROOT 
RETURN sys_refcursor AS 

  refC sys_refcursor;
BEGIN

  OPEN refC FOR
    SELECT
      '10' ALM,
      '1' LOC,
      'DE' NAT
    FROM DUAL
    UNION ALL
    SELECT
      '10' ALM,
      '2' LOC,
      'DE' NAT
    FROM DUAL
  ;

  RETURN refC;
END F_XML_WITHOUT_ROOT;

Then i change the primary SELECT to make the entire XML:

SELECT XMLSerialize(content

    XMLElement("Group", XMLAttributes('I' AS "OP")
    , XMLForest(
          3 FIL
        , 59 TPD
    ) 
    , XMLElement("Obs"
        , XMLForest(
          'N' OB_CH_TYPE
          , (
            'Ref. '
          ) OB_ST_OBS
        )
      )

      , (
        SELECT
          XMLAgg(
            XMLElement("Item", XMLAttributes('I' AS "OP")
              , XMLElement("ITN",1)
              , 
              (SELECT
                XMLAgg(
                  XMLElement("Item", 
                     XMLElement("ALM", ALM) 
                    ,XMLElement("LOC", LOC)
                    ,XMLElement("NAT", NAT)
                  )
                ) 
                FROM 
                XMLTABLE(
                  '/ROWSET/ROW'
                  PASSING XMLType(MGCLI.F_XML_WITHOUT_ROOT())
                  COLUMNS
                  ALM  PATH 'ALM',
                  LOC PATH 'LOC',
                  NAT PATH  'NAT'
                )
              ) 
            )
          ) FROM DUAL
        )

      ).extract('/*') indent
    ) XML_BL_XML
        FROM DUAL;

And the result:

<Group OP="I">
  <FIL>3</FIL>
  <TPD>59</TPD>
  <Obs>
    <OB_CH_TYPE>N</OB_CH_TYPE>
    <OB_ST_OBS>Ref. </OB_ST_OBS>
  </Obs>
  <Item OP="I">
    <ITN>1</ITN>
    <Item>
      <ALM>10</ALM>
      <LOC>1</LOC>
      <NAT>DE</NAT>
    </Item>
    <Item>
      <ALM>10</ALM>
      <LOC>2</LOC>
      <NAT>DE</NAT>
    </Item>
  </Item>
</Group>

This is the best way i find, maybe has another...