This discussion is archived
4 Replies Latest reply: Aug 8, 2012 6:58 AM by Marwim RSS

Store XML-fragment without Namespace Information

Marwim Expert
Currently Being Moderated
Hello,

I register a schema, create a table with a XMLTYPE column, insert a row and create a view to query the data.
ALTER SESSION SET nls_numeric_characters = '.,';
BEGIN
    dbms_xmlschema.registerSchema(
         'http://test_datetime.xsd'
        ,q'[<?xml version="1.0" encoding="WE8ISO8859P1" standalone="no"?>
 <xs:schema xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb" targetNamespace="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99" elementFormDefault="qualified">
  <xs:element name="Document" type="Document"/>
    <xs:complexType name="Document">
        <xs:sequence>
            <xs:element name="CreDtTm" type="ISODateTime"/>
        </xs:sequence>
    </xs:complexType>
    <xs:simpleType name="ISODateTime" xdb:SQLType="TIMESTAMP WITH TIME ZONE">
        <xs:restriction base="xs:dateTime"/>
    </xs:simpleType>
</xs:schema>]'
        ,TRUE
        ,FALSE
        ,FALSE
        );
END;
/
CREATE TABLE test_datetime (
     id             NUMBER
    ,xml_document   XMLTYPE
    )
    XMLTYPE COLUMN xml_document
    ELEMENT "pain.001.002.99.xsd#Document";

INSERT INTO test_datetime (id,xml_document)
    VALUES (
         1
        ,XMLTYPE(
q'[<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99
pain.001.002.99.xsd">
 <CreDtTm>2012-06-02T09:30:47.000Z</CreDtTm>
</Document>]')
    );
COMMIT;
CREATE OR REPLACE VIEW v_dateTime_xml AS
SELECT  created.CreationDateTime
       ,created.CreDtTm
FROM    test_datetime,
        XMLTABLE(XMLNAMESPACES(DEFAULT 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.99'),
            '/Document'
            PASSING test_datetime.xml_document
            COLUMNS
             CreationDateTime TIMESTAMP WITH TIME ZONE  PATH 'CreDtTm'
            ,CreDtTm          XMLTYPE                   PATH 'CreDtTm'
            ) created;
I want to store the element CreDtTm in another table to use it later without recreating it (in my real code it is not a simple element, but a fragment with many elements).
Yet the selected element contains the schema information
<CreDtTm xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99">2012-06-02T09:30:47.000000+00:00</CreDtTm>
Therefore, when I later use it in another XML document it is includes together with the xmlns attribute.
SELECT  XMLELEMENT(
             "Document"
            ,XMLAttributes(
                 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.99' AS "xmlns"
                ,'http://www.w3.org/2001/XMLSchema-instance' AS "xmlns:xsi"
                ,'urn:iso:std:iso:20022:tech:xsd:pain.001.002.99 pain.001.002.99.xsd' AS "xsi:schemaLocation"
                )
            ,(  SELECT  XMLAGG(CreDtTm)
                FROM    v_dateTime_xml
                )
        )
FROM    dual;

<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99 pain.001.002.99.xsd">
 <CreDtTm xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99">2012-06-02T09:30:47.000000+00:00</CreDtTm>
</Document>
How can I store or retrieve it without the schema information?

Regards
Marcus

Edited by: Marwim on 08.08.2012 14:06
Corrected schema
  • 1. Re: Store XML-fragment without Namespace Information
    odie_63 Guru
    Currently Being Moderated
    Hi Marcus,

    For the record, your test case is not consistent (different target namespace and schema urls).

    As for the issue, it's not really one actually. The namespace redefinition at a lower level doesn't change the semantic of the element.

    Stripping namespaces from a document/fragment is not something trivial.
    In the XML data model, the namespace is a part of the element qualified name (QName). Removing a namespace means changing the QName and that requires processing the entire subtree recursively to propagate the change to child elements in the same (default) namespace.

    That can be done with XSLT (identity-based template) or an XQuery recursive function.
    Although not very difficult, does it worth the effort?


    BTW, now that you're finally using a schema-based XMLType column to store documents, you could benefit from Object-Relational storage and XPath rewrite. For that, you'll have to use "genTypes => true" on schema registration.

    Edited by: odie_63 on 8 août 2012 13:52
  • 2. Re: Store XML-fragment without Namespace Information
    Marwim Expert
    Currently Being Moderated
    Hello Marc,
    Although not very difficult, does it worth the effort?
    Maybe the fragments will be used in another document too - but I will deal with this later, when it is unavoidable ;-)

    Regards
    Marcus


    P.S.: Perhaps something dirty like
    SELECT  XMLTYPE(
                REPLACE(
                     XMLSERIALIZE(DOCUMENT CreDtTm)
                    ,' xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.002.99"'
                    )
                )
    FROM    v_dateTime_xml;
    Edited by: Marwim on 08.08.2012 14:24
    Added P.S.
  • 3. Re: Store XML-fragment without Namespace Information
    odie_63 Guru
    Currently Being Moderated
    P.S.: Perhaps something dirty like
    Sure, you can always do that :)


    Here are two examples with XQuery or XSLT :
    SQL> var xsldoc varchar2(4000)
    SQL> 
    SQL> begin
      2  
      3   :xsldoc := '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      4    <xsl:output method="xml" omit-xml-declaration="yes"/>
      5    <xsl:template match="*">
      6      <xsl:element name="{local-name()}">
      7        <xsl:apply-templates select="@*|*|text()"/>
      8      </xsl:element>
      9    </xsl:template>
     10    <xsl:template match="@*|text()">
     11      <xsl:copy/>
     12    </xsl:template>
     13  </xsl:stylesheet>';
     14  
     15  end;
     16  /
     
    PL/SQL procedure successfully completed
     
    SQL> 
    SQL> SELECT XMLQuery(
      2         'declare function local:strip-ns($e as element()) as element()
      3          {
      4            element {local-name($e)}
      5            {
      6              for $i in $e/(@*|node())
      7              return typeswitch ($i)
      8                       case element() return local:strip-ns($i)
      9                       default return $i
     10            }
     11          }; local:strip-ns(*)'
     12          passing x.CreDtTm
     13          returning content
     14         ) as "XQuery method"
     15       , XMLTransform(x.CreDtTm, :xsldoc) as "XSLT method"
     16  FROM test_datetime
     17     , XMLTable(
     18         XMLNamespaces(default 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.99')
     19       , '/Document'
     20         PASSING test_datetime.xml_document
     21         COLUMNS CreDtTm   XMLTYPE PATH 'CreDtTm'
     22       ) x
     23  ;
     
    XQuery method                                                                    XSLT method
    -------------------------------------------------------------------------------- --------------------------------------------------------------------------------
    <CreDtTm> 2012-06-02T09:30:47,000000+00:00</CreDtTm>                             <CreDtTm> 2012-06-02T09:30:47,000000+00:00</CreDtTm>
     
  • 4. Re: Store XML-fragment without Namespace Information
    Marwim Expert
    Currently Being Moderated
    Here are two examples with XQuery or XSLT :
    Great, I'm sure you did this just to show me, that I still have a long way to go before I can really utilize the power of XML ;-)

    Regards
    Marcus

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points