Oracle8i Application Developer's Guide - XML Release 3 (8.1.7) Part Number A86030-01 |
Library | Service | Contents | Index

Using XML Parser for Java, 14 of 22

## DTDs

### Checking DTD Syntax: Suggestions for Editors

#### Question

I was wondering if someone could help me verify the syntax for the following DTD. I realize that I can use a DTD editor to do this for me, but the editor I'm using is not very good.

     <?xml version="1.0"?>
     <!DOCTYPE CATALOG [

     <!ELEMENT CATALOG ( ADMIN, SCHEMA?, DATA? ) >
     <!ATTLIST CATALOG xml:lang NMTOKEN #IMPLIED >

     <!ELEMENT ADMIN ( NAME, INFORMATION) >
     <!ELEMENT SCHEMA (CATEGORY | DESCRIPTOR)* >
     <!ELEMENT DATA (ITEM)*>

     <!ELEMENT NAME (#PCDATA) >
     <!ELEMENT INFORMATION ( DATE, SOURCE )  >
     <!ELEMENT DATE (#PCDATA) >
     <!ELEMENT SOURCE (#PCDATA) >

     <!ELEMENT CATEGORY (NAME | KEY | TYPE | UPDATE  )* >
     <!ATTLIST CATEGORY ACTION (ADD|DELETE|UPDATE) #REQUIRED>
     <!ELEMENT DESCRIPTOR (NAME | KEY | UPDATE | OWNER  | TYPE )* >
     <!ATTLIST DESCRIPTOR ACTION (ADD|DELETE|UPDATE) #REQUIRED>
     <!ELEMENT OWNER (NAME?, KEY? ) >
     <!ELEMENT KEY (#PCDATA) >
     <!ELEMENT TYPE (#PCDATA) >

     <!ELEMENT ITEM (OWNER?, NAMEVALUE*, UPDATE ) >
     <!ATTLIST ITEM ACTION (ADD | DELETE | UPDATE) #REQUIRED>
     <!ELEMENT UPDATE (NAME | KEY | NAMEVALUE )* >

     <!ELEMENT NAMEVALUE ( NAME, VALUE ) >
     <!ELEMENT VALUE (#PCDATA)* >
     ]>

I'm unsure about the ATTLIST syntax.

#### Answer

I loaded this into XMLAuthority 1.1 and did a Save As. XML Authority lets you visually inspect and edit DTD's and XML Schemas. Highly recommended. http://www.extensibility.com. ($99.00).

It came back with:

    <!ELEMENT CATALOG  (ADMIN , SCHEMA? , DATA? )>
    <!ATTLIST CATALOG  xml:lang NMTOKEN  #IMPLIED >
    <!ELEMENT ADMIN  (NAME , INFORMATION )>
    <!ELEMENT SCHEMA  (CATEGORY | DESCRIPTOR )*>
    <!ELEMENT DATA  (ITEM )*>
    <!ELEMENT NAME  (#PCDATA )>
    <!ELEMENT INFORMATION  (DATE , SOURCE )>
    <!ELEMENT DATE  (#PCDATA )>
    <!ELEMENT SOURCE  (#PCDATA )>
    <!ELEMENT CATEGORY  (NAME | KEY | TYPE | UPDATE )*>
    <!ATTLIST CATEGORY  ACTION  (ADD | DELETE | UPDATE )  #REQUIRED >
    <!ELEMENT DESCRIPTOR  (NAME | KEY | UPDATE | OWNER | TYPE )*>
    <!ATTLIST DESCRIPTOR  ACTION  (ADD | DELETE | UPDATE )  #REQUIRED >
    <!ELEMENT OWNER  (NAME? , KEY? )>
    <!ELEMENT KEY  (#PCDATA )>
    <!ELEMENT TYPE  (#PCDATA )>
    <!ELEMENT ITEM  (OWNER? , NAMEVALUE* , UPDATE )>
    <!ATTLIST ITEM  ACTION  (ADD | DELETE | UPDATE )  #REQUIRED >
    <!ELEMENT UPDATE  (NAME | KEY | NAMEVALUE )*>
    <!ELEMENT NAMEVALUE  (NAME , VALUE )>
    <!ELEMENT VALUE  (#PCDATA )*>

### DTD File in DOCTYPE Must be Relative to XML Document Location

#### Question

My parser doesn't find the DTD file.

#### Answer

The DTD file defined in the <!DOCTYPE> declaration must be relative to the location of the input XML document. Otherwise, you'll need to use the setBaseURL(url) functions to set the base URL to resolve the relative address of the DTD if the input is coming from an InputStream.

### Validating an XML File Using External DTD

#### Question

Can I validate an XML file using an external DTD?

#### Answer

You need to include a reference to the applicable DTD in your XML document. Without it there is no way that the parser knows what to validate against. Including the reference is the XML standard way of specifying an external DTD. Otherwise you need to embed the DTD in your XML Document.

### DTD Caching

#### Question

Do you have DTD caching? How do I set the DTD using v2 parser for DTD Cache purpose?

#### Answer

Yes, DTD caching is optional and is not enabled automatically.

The method to set the DTD is setDoctype(). Here is an example:

    // Test using InputSource
    parser = new DOMParser();
    parser.setErrorStream(System.out);
    parser.showWarnings(true);

    FileReader r = new FileReader(args[0]);
    InputSource inSource = new InputSource(r);
    inSource.setSystemId(createURL(args[0]).toString());
    parser.parseDTD(inSource, args[1]);
    dtd = (DTD)parser.getDoctype();

    r = new FileReader(args[2]);
    inSource = new InputSource(r);
    inSource.setSystemId(createURL(args[2]).toString());
    parser.setDoctype(dtd);
    parser.setValidationMode(true);
    parser.parse(inSource);

    doc = (XMLDocument)parser.getDocument();
    doc.print(new PrintWriter(System.out));

### Recognizing External DTDs

#### Question

How can XML Parser for Java (V2) recognize external DTD's when running from the server. The Java code has been loaded with loadjava and runs in the Oracle8i server process. My XML file has an external DTD reference.

1. But is there a more generic way, as with the SAX parser, to redirect it to a stream or string or something if my DTD is in the database?

2. Do you have a more generic way to redirect the DTD, analogous to that offered by the SAXParser with resolveEntity().

#### Answer

1. We only have the setBaseURL() method at this time.

2. You can achieve your desired result using the following:

   1. Parse your External DTD using a DOMParser's parseDTD() method.

   2. Call getDoctype() to get an instance of oracle.xml.parser.v2.DTD

   3. On the document where you want to set your DTD programmatically, use the: setDoctype( yourDTD ); We use this technique to read a DTD out of our product's JAR file..

### Loading external DTD's from a jar File

#### Question

I would like to put all my DTDs in a jar file, so then when the XML Parser needs a DTD it can get it from the jar. The XML Parser right now supports a base URL(setBaseURL()), but that just points to a place where all the DTDs are exposed.

#### Answer

The solution involves a combination of:

1. Load DTD as InputStream using:

       InputStream is =
       YourClass.class.getResourceAsStream("/foo/bar/your.dtd");

   This will open ./foo/bar/your.dtd in the first relative location on the CLASSPATH that it can be found, including out of your jar if it's in the CLASSPATH.

2. Parse the DTD with the code:

       DOMParser d = new DOMParser();
       d.parseDTD(is, "rootelementname");
       d.setDoctype(d.getDoctype());

3. Now parse your document with:

       d.parse("yourdoc");

### Can I Check the Correctness of an XML Document Using their DTD?

#### Question

I am exporting Java objects to XML. I can construct a DOM with a XMLDocument and use its print method to export it. But, I am unable to set the DTD of these documents. I construct a parser, parse the DTD, and then get the DTD viaDocument doc = parser.getDocument() andDocType dtd = doc.getDocumentType().

How do I set the DTD of the freshly constructed XMLDocuments to use this one in order to be able to check the correctness of the documents using this DTD at a later time?

#### Answer

Your method of getting the DTD object is correct. However, we do not do any validation while creating the DOM tree using DOM APIs. So setting the DTD in the Document will not help validate the DOM tree that is constructed. The only way to validate an XML file is to parse the XML document using DOMParser or SAXParser.

### Parsing a DTD Object Separately from XML Document

#### Question

How do I parse and get a DTD Object seperately from parsing my XML document?

#### Answer

The parseDTD() method allows you to parse a DTD file separately and get a DTD object. Here is a sample code to do that:

    DOMParser domparser = new DOMParser();
    domparser.setValidationMode(true);
    /* parse the DTD file */
    domparser.parseDTD(new FileReader(dtdfile));
    DTD dtd = domparser.getDocType();

### Case-Sensitivity in Parser Validation against DTD?

#### Question

The XML file has a tag like : <xn:subjectcode>. In the DTD, it is defined as `<xn:subjectCode>`. When the file is parsed and validated against the DTD, it gives an error: XML-0148 : (Error) Invalid element 'xn:subjectcode' in content of 'xn:Resource', ...

When I changed the element name to <xn:subjectCode> instead of <xn:subjectcode> it works. Is the parser case-sensitive as far as validation against DTD's go - or is it because, there is a namespace also in the tag definition of the element and when a element is defined along with its namespace, the case-sensitivity comes into effect?

#### Answer

XML is inherently case-sensitive, therefore our parsers enforce case sensitivity in order to be compliant. When you run in non-validation mode only well-formness counts. However <test></Test> would signal an error even in non-validation mode.

### Extracting Embedded XML From a CDATA Section

#### Question

1. I want to extract PAYLOAD and do extra processing on it.

2. When I select the value of PAYLOAD it does not parse the data because it is in a CDATA section.

3. How do I extract embedded XML using just XSLT. I have done this using SAX before but in the current setup all I can use is XSLT.

#### Answer

1. Here are the answers:

       <PAYLOAD>
       <![CDATA[<?xml version = '1.0' encoding = 'ASCII' standalone = 'no'?>
       <ADD_PO_003>
          <CNTROLAREA>
             <BSR>
                <VERB value="ADD">ADD</VERB>
                <NOUN value="PO">PO</NOUN>
                <REVISION value="003">003</REVISION>
             </BSR>
          </CNTROLAREA>
       </ADD_PO_003>]]>
       </PAYLOAD>

   The CDATA strategy is kind of odd. You won't be able to use a different encoding on the nested XML document included as text inside the CDATA, so having the XML Declaration of the embedded document seems of little value to me. If you don't need the XML Declaration, then why not just embded the message as real elements into the <PAYLOAD> instead of as a text chunk which is what CDATA does for you.

   Just do:

       String s = YourDocumentObject.selectSingleNode("/OES_MESSAGE/PAYLOAD");

2. It shouldn't parse the data, you've asked for it to be a big text chunk, which is what it will give you. You'll have to parse the text chunk yourself (another benefit of not using the CDATA approach) by doing something like:

         YourParser.parse( new StringReader(s));

   where s is the string you got in the previous step.

3. There's nothing special about what's in your CDATA, it's just text. If you want the text content to be output without escaping the angle-brackets, then you'll do:

        <xsl:value-of select="/OES_MESSAGE/PAYLOAD" disable-output-escaping="yes"/>

| Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
Library | Service | Contents | Index