xmloracle-databaseplsqlxquery-sql

XQuery : xml declaration is dropped when if statement is used


Consider the following three statements.

1:

XMLSERIALIZE(DOCUMENT XMLQUERY(q'^
                                copy $i := $doc modify (
                                    for $j in $i/tdfmt/text()[1]
                                return 
                                    insert node ( $text, $br, '
' ) before $j
                                )
                                return $i
                               ^'
        PASSING
            XMLTYPE(OIT.INFTXT)  AS "doc",
            LENGTH(EXTRACTVALUE(XMLTYPE(OIT.INFTXT),'tdfmt/text()[1]')) AS "len",
            'NEW TEXT TO INSERT' AS "text",
            XMLTYPE('<br/>')            AS "br"
        RETURNING CONTENT)  AS CLOB INDENT SIZE=4 )
        AS NEW_INFTXT_A

2:

XMLSERIALIZE(DOCUMENT XMLQUERY(q'^
                                copy $i := $doc modify (
                                    for $j in $i/*
                                return 
                                    insert node ( $text, $br, '&#xa;' ) into $j
                                )
                                return $i
                               ^'
        PASSING
            XMLTYPE(OIT.INFTXT)  AS "doc",
            LENGTH(EXTRACTVALUE(XMLTYPE(OIT.INFTXT),'tdfmt/text()[1]')) AS "len",
            'NEW TEXT TO INSERT' AS "text",
            XMLTYPE('<br/>')            AS "br"
        RETURNING CONTENT)  AS CLOB INDENT SIZE=4 )
        AS NEW_INFTXT_B

3:

XMLSERIALIZE(DOCUMENT XMLQUERY(q'^                                      
                                if ($len>0) 
                                then    
                                    copy $i := $doc modify (
                                        for $j in $i/tdfmt/text()[1]
                                    return 
                                        insert node ( $text, $br, '&#xa;' ) before $j
                                    )
                                    return $i
                                else    
                                    copy $i := $doc modify (
                                        for $j in $i/*
                                    return 
                                        insert node ( $text, $br, '&#xa;' ) into $j
                                    )
                                    return $i
                               ^'
        PASSING
            XMLTYPE(OIT.INFTXT)  AS "doc",
            LENGTH(EXTRACTVALUE(XMLTYPE(OIT.INFTXT),'tdfmt/text()[1]')) AS "len",
            'NEW TEXT TO INSERT' AS "text",
            XMLTYPE('<br/>')            AS "br"
        RETURNING CONTENT)  AS CLOB INDENT SIZE=4 )
        AS NEW_INFTXT1

The idea is to switch between 1 and 2 depending on the length of my node. In the output of 3, I noticed that the xml declaration <?xml version="1.0"?> is omitted while with 1 and 2 it is present. Any idea why adding an if then else statement would cause this behaviour and what I should to to prevent the declaration form being dropped.


Solution

  • Not sure why it has that effect, but you can avoid it by putting the if within the modify:

    XMLSERIALIZE(DOCUMENT XMLQUERY(q'^                                      
                                    copy $i := $doc modify (
                                        if ($len>0) 
                                        then    
                                            for $j in $i/tdfmt/text()[1]
                                            return 
                                            insert node ( $text, $br, '&#xa;' ) before $j
                                        else    
                                            for $j in $i/*
                                            return 
                                            insert node ( $text, $br, '&#xa;' ) into $j
                                    )
                                    return $i
                                   ^'
            PASSING
                XMLTYPE(OIT.INFTXT)  AS "doc",
                LENGTH(EXTRACTVALUE(XMLTYPE(OIT.INFTXT),'tdfmt/text()[1]')) AS "len",
                'NEW TEXT TO INSERT' AS "text",
                XMLTYPE('<br/>')            AS "br"
            RETURNING CONTENT)  AS CLOB INDENT SIZE=4 )
            AS NEW_INFTXT1
    

    You can also test for the existence of the node in the FLWOR, rather than passing $len in:

    XMLSERIALIZE(DOCUMENT XMLQUERY(q'^                                      
                copy $i := $doc modify (
                    if (exists($i/tdfmt/text()[1])) 
                    then    
                        for $j in $i/tdfmt/text()[1]
                            return insert node ( $text, $br, $newline ) before $j
                    else    
                        for $j in $i/*
                            return insert node ( $text, $br, $newline ) into $j
                )
                return $i
                ^'
            PASSING
                XMLTYPE(OIT.INFTXT)  AS "doc",
                'NEW TEXT TO INSERT' AS "text",
                XMLTYPE('<br/>') AS "br",
                CHR(10) AS "newline"
            RETURNING CONTENT)  AS CLOB INDENT SIZE=4 )
            AS NEW_INFTXT1
    

    (also changed to pass $newline in as shown in a previous answer, just because I think it looks neater *8-)

    fiddle