home *** CD-ROM | disk | FTP | other *** search
/ Dynamic HTML in Action / Dynamicke-HTML-v-akci-covermount.bin / XML / PARSER / XMLINST.EXE / classes / com / ms / xml / parser / DTD.java < prev    next >
Encoding:
Java Source  |  1997-11-03  |  11.1 KB  |  428 lines

  1. /*
  2.  * @(#)Document.java 1.0 6/3/97
  3.  * 
  4.  * Copyright (c) 1997 Microsoft, Corp. All Rights Reserved.
  5.  * 
  6.  */
  7.  
  8. package com.ms.xml.parser;
  9.  
  10. import com.ms.xml.om.Element;
  11. import com.ms.xml.om.ElementImpl;
  12. import com.ms.xml.util.Name;
  13. import com.ms.xml.util.Atom;
  14. import com.ms.xml.util.XMLOutputStream;
  15. import com.ms.xml.util.EnumWrapper;
  16.  
  17. import java.util.Vector;
  18. import java.lang.String;
  19. import java.util.Hashtable;
  20. import java.util.Enumeration;
  21. import java.io.IOException;
  22.  
  23.  
  24. /**
  25.  * This class contains all the Document Type Definition (DTD) 
  26.  * information for an XML document.
  27.  *
  28.  * @version 1.0, 6/17/97
  29.  */
  30. public class DTD
  31. {
  32.     /**
  33.      * Creates a new empty DTD.
  34.      */
  35.     public DTD()
  36.     {        
  37.     }
  38.  
  39.     /** 
  40.      * Finds a named entity in the DTD.
  41.      * @param n  The name of the entity.
  42.      * @return  the specified <code>Entity</code> object; returns null if it 
  43.       * is not found. 
  44.      */
  45.     final void addEntity(Entity en)
  46.     {        
  47.         if (entities == null)
  48.         {
  49.             entities = new Hashtable();
  50.         }        
  51.         entities.put(en.name, en);
  52.     }
  53.     
  54.     public final Entity findEntity(Name n)
  55.     {
  56.         // First see if fully qualified entity is defined in DTD
  57.         Object o = null;
  58.         if (entities != null) {
  59.             o = (Entity)entities.get(n);
  60.         }
  61.         // Then see if the entity minus the namespace matches 
  62.         // a built in entity.  This allows & to be used in
  63.         // the scope of another namespace, otherwise the user
  64.         // would have to use &::amp; which is wierd.
  65.         if (o == null) {
  66.             o = builtin.get(n.getName());
  67.         }
  68.         if (o != null)
  69.         {
  70.             return (Entity)o;
  71.         }
  72.         return null;
  73.     }
  74.  
  75.     final void addElementDecl(ElementDecl ed)
  76.     {        
  77.         if (elementdecls == null)
  78.         {
  79.             elementdecls = new Hashtable();
  80.         }
  81.         elementdecls.put(ed.name, ed);
  82.     }
  83.     
  84.     /** 
  85.      * Finds an element declaration for the given tag name.
  86.      * @param name  The tag name.
  87.      * @return  the element declaration object. 
  88.      */
  89.     public final ElementDecl findElementDecl(Name name)
  90.     {
  91.         return elementdecls == null ? null : (ElementDecl)elementdecls.get(name);
  92.     }
  93.  
  94.     /**
  95.      * Retrieves an object for enumerating the element declarations.
  96.      * 
  97.      * @return  an <code>Enumeration</code> object that returns 
  98.      * <code>ElementDecl</code> objects when enumerated. 
  99.      */
  100.     public final Enumeration elementDeclarations()
  101.     {
  102.         return elementdecls == null ? EnumWrapper.emptyEnumeration : elementdecls.elements();
  103.     }
  104.  
  105.     /**
  106.      * Return an enumeration for enumerating the entities
  107.      * The enumeration returns entity objects.
  108.      */
  109.     public final Enumeration entityDeclarations()
  110.     {
  111.         return entities == null ? EnumWrapper.emptyEnumeration : entities.elements();
  112.     }
  113.  
  114.     /**
  115.      * Return an enumeration for enumerating the notations
  116.      * The enumeration returns notation objects.
  117.      */
  118.     public final Enumeration notationDeclarations()
  119.     {
  120.         return notations == null ? EnumWrapper.emptyEnumeration : notations.elements();
  121.     }
  122.  
  123.     final void addNotation(Notation no)
  124.     {        
  125.         if (notations == null)
  126.         {
  127.             notations = new Hashtable();
  128.         }
  129.         notations.put(no.name, no);
  130.     }
  131.     
  132.     /**
  133.      * Retrieves the named XML notation in the DTD.
  134.      *
  135.      * @param name  The name of the notation.
  136.      * @return the <code>Notation</code> object; returns null if it is not 
  137.       * found.
  138.      */
  139.     public final Notation findNotation(Name name)
  140.     {
  141.         return notations == null ? null : (Notation)notations.get(name);
  142.     }
  143.  
  144.     /**
  145.      *    add a <long name, short name> pair to the name space hashtable 
  146.      */
  147.     public final void addNameSpace(Atom as, Atom href)
  148.     {
  149.         if (shortNameSpaces == null)
  150.         {
  151.             shortNameSpaces = new Hashtable();
  152.             longNameSpaces = new Hashtable();
  153.         }
  154.         shortNameSpaces.put(href, as);
  155.         longNameSpaces.put(as, href);
  156.     }
  157.  
  158.     /**
  159.      * get the short name of a specified name space
  160.      */
  161.     public final Atom findShortNameSpace(Atom href)
  162.     {
  163.         return shortNameSpaces == null ? null : (Atom)shortNameSpaces.get(href);
  164.     }
  165.  
  166.     public final Atom findLongNameSpace(Atom as)
  167.     {
  168.         return longNameSpaces == null ? null : (Atom)longNameSpaces.get(as);
  169.     }
  170.  
  171.     static public boolean isReservedNameSpace(Atom n)
  172.     {
  173.         return (n == nameXML);
  174.     }
  175.  
  176.     /**
  177.      *    keep a list of all name spaces loaded so they are loaded twice if 
  178.      *  two name spaces happen to refer to the same DTD file
  179.      */
  180.     public final Atom findLoadedNameSpace(Atom url)
  181.     {
  182.         if (url == null) return null;
  183.         return loadedNameSpaces == null ? null : (Atom)loadedNameSpaces.get(url);
  184.     }
  185.  
  186.     /**
  187.      * add a loaded name space name to the list
  188.      */
  189.     public final void addLoadedNameSpace(Atom url)
  190.     {
  191.         if (loadedNameSpaces == null)
  192.         {
  193.             loadedNameSpaces = new Hashtable();
  194.         }
  195.         loadedNameSpaces.put(url, url);
  196.     }
  197.     
  198.     final void addID(Name name, Element e)
  199.     {        
  200.         if (ids == null)
  201.         {
  202.             ids = new Hashtable();
  203.         }
  204.         ids.put(name, e);
  205.     }
  206.  
  207.     final Element findID(Name name)
  208.     {
  209.         return ids == null ? null : (Element)ids.get(name);
  210.     }
  211.  
  212.     final void addIDCheck(Name name, int line, int col, Object owner)
  213.     {
  214.         idCheck = new IDCheck(idCheck, name, line, col, owner);
  215.     }
  216.     
  217.     final void checkIDs() throws ParseException
  218.     {
  219.         while(idCheck != null)
  220.         {
  221.             if (findID(idCheck.name) == null)
  222.             {
  223.                 throw new ParseException("Couldn't find element with ID '" + idCheck.name.toString() + "'", 
  224.                     idCheck.line, idCheck.col, idCheck.owner);
  225.             }
  226.             idCheck = idCheck.next;
  227.         }
  228.     }
  229.  
  230.     /**
  231.      * Convert everything stored in the DTD to schema.  (Does not retain original order)
  232.      */
  233.     final public Element getSchema()
  234.     {
  235.         if( schema == null )
  236.         {
  237.             schema = new ElementImpl( Name.create("SCHEMA","XML"), Element.ELEMENT );
  238.             if( docType != null )
  239.                 schema.setAttribute( Name.create("ID","XML"), docType );
  240.  
  241.             Enumeration e;
  242.             if (longNameSpaces != null)
  243.             {
  244.                 e = longNameSpaces.keys();
  245.                 for( ; e.hasMoreElements(); )
  246.                 {
  247.                     Atom as = (Atom)e.nextElement();
  248.                     Element ns = new ElementImpl( Name.create("NAMESPACE","XML"), Element.PI );
  249.                     ns.setAttribute(Name.create("HREF","XML"),longNameSpaces.get(as));
  250.                     ns.setAttribute(Name.create("AS","XML"),as);
  251.                     schema.addChild( ns, null );
  252.                 }
  253.             }
  254.  
  255.             e = notationDeclarations();
  256.             for( ; e.hasMoreElements(); )
  257.             {
  258.                 Element curr = (Element)e.nextElement();
  259.                 Element currSchema = curr.toSchema();
  260.                 if( currSchema != null )
  261.                     schema.addChild( currSchema, null );
  262.             }
  263.  
  264.             e = entityDeclarations();
  265.             for( ; e.hasMoreElements(); )
  266.             {
  267.                 Element curr = (Element)e.nextElement();
  268.                 Element currSchema = curr.toSchema();
  269.                 if( currSchema != null )
  270.                     schema.addChild( currSchema, null );
  271.             }
  272.  
  273.             e = elementDeclarations();
  274.             for( ; e.hasMoreElements(); )
  275.             {
  276.                 Element curr = (Element)e.nextElement();
  277.                 Element currSchema = curr.toSchema();
  278.                 if( currSchema != null )
  279.                     schema.addChild( currSchema, null );
  280.             }
  281.         }
  282.  
  283.         return schema;
  284.     }
  285.  
  286.     /**
  287.      * Saves the DTD information to the given XML output stream.
  288.      * @param o  The output stream to write to.
  289.       * @return No return value.
  290.      * @exception  IOException if there are problems writing to the output 
  291.       * stream.
  292.      */
  293.     final public void save(XMLOutputStream o) throws IOException {
  294.         if (notations != null) {
  295.             Enumeration e = notations.elements();
  296.             while (e.hasMoreElements()) {
  297.                 Notation n = (Notation)e.nextElement();
  298.                 o.writeIndent();
  299.                 n.save(o);
  300.             }
  301.         }
  302.         if (entities != null) {
  303.             Enumeration e = entities.elements();
  304.             while (e.hasMoreElements()) {
  305.                 Entity en = (Entity)e.nextElement();
  306.                 o.writeIndent();
  307.                 en.save(o);
  308.             }
  309.         }
  310.         if (elementdecls != null) {
  311.             Enumeration e = elementdecls.elements();
  312.             while (e.hasMoreElements()) {
  313.                 ElementDecl decl = (ElementDecl)e.nextElement();
  314.                 o.writeIndent();
  315.                 decl.save(o);
  316.             }
  317.         }
  318.     }
  319.  
  320.     /**
  321.      * Resets the DTD to its initial state.
  322.       * @return No return value.
  323.      */
  324.     final public void clear()
  325.     {
  326.         if (ids != null) ids.clear();
  327.         idCheck = null;
  328.     }
  329.  
  330.     /**
  331.      * Retrieves the name specified in the <code>DOCTYPE</code> tag.
  332.      * @return  the name of the document type.
  333.      */
  334.     final public Name getDocType()
  335.     {
  336.         return docType;
  337.     }
  338.  
  339.     /**
  340.      * Entity storage
  341.      */    
  342.     static Hashtable builtin;
  343.     Hashtable entities;
  344.  
  345.     /**
  346.      * ElementDecl storage
  347.      */
  348.     Hashtable elementdecls;
  349.  
  350.     /**
  351.      * Notation storage
  352.      */    
  353.     Hashtable notations;
  354.  
  355.     /**
  356.      *    Name space storage, index from long name to short name
  357.      */
  358.     Hashtable shortNameSpaces;
  359.  
  360.     /**
  361.      *  Name space storage, index from short name to long name
  362.      */
  363.     Hashtable longNameSpaces;
  364.  
  365.     /**
  366.      * a hashtable of loaded name spaces
  367.      */
  368.     Hashtable loadedNameSpaces;
  369.  
  370.     /**
  371.      * ID storage
  372.      */
  373.     transient Hashtable ids;
  374.  
  375.     /**
  376.      * IDs to check later for matching elements
  377.      */
  378.     transient IDCheck idCheck;
  379.  
  380.     /**
  381.      * document type name
  382.      */
  383.     Name docType;
  384.  
  385.     /**
  386.      * Schema representation
  387.      */    
  388.     Element schema = null;
  389.  
  390.     static Atom nameXML = Atom.create("XML");
  391.         
  392.     static
  393.     {
  394.         builtin = new Hashtable();
  395.         String n = "apos";
  396.         builtin.put("apos", new Entity(Name.create(n), false, 39));
  397.         n = "quot";
  398.         builtin.put(n, new Entity(Name.create(n), false, 34));  
  399.         n = "amp";
  400.         builtin.put(n, new Entity(Name.create(n), false, 38));
  401.         n = "lt";
  402.         builtin.put(n, new Entity(Name.create(n), false, 60));
  403.         n = "gt";
  404.         builtin.put(n, new Entity(Name.create(n), false, 62));
  405.         n = "nbsp";
  406.         builtin.put(n, new Entity(Name.create(n), false, 160));
  407.     }
  408. }
  409.  
  410. class IDCheck
  411. {
  412.     Name name;
  413.     int line;
  414.     int col;
  415.     Object owner;
  416.     IDCheck next;
  417.  
  418.     IDCheck(IDCheck next, Name name, int line, int col, Object owner)
  419.     {
  420.         this.next = next;
  421.         this.name = name;
  422.         this.line = line;
  423.         this.col = col;
  424.         this.owner = owner;
  425.     }
  426. }
  427.  
  428.