4 Replies Latest reply: Aug 8, 2012 8:58 AM by Marwim RSS

    Store XML-fragment without Namespace Information

    Marwim
      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
          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
            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
              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
                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