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 / AttDef.java < prev    next >
Encoding:
Java Source  |  1997-12-01  |  13.1 KB  |  507 lines

  1. /*
  2.  * @(#)AttDef.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.  
  16. import java.io.IOException;
  17. import java.util.Vector;
  18. import java.util.Enumeration;
  19.  
  20. /**
  21.  * This object describes an attribute type and potential values.
  22.  * This encapsulates the information for one Attribute in an
  23.  * Attribute List in a DTD as described below:
  24.  */
  25. public class AttDef
  26. {
  27.     /**
  28.      * type of attribute
  29.      */    
  30.     public static final int CDATA      = 0;
  31.     public static final int ID         = 1;
  32.     public static final int IDREF      = 2;
  33.     public static final int IDREFS     = 3;
  34.     public static final int ENTITY     = 4;
  35.     public static final int ENTITIES   = 5;
  36.     public static final int NMTOKEN    = 6;
  37.     public static final int NMTOKENS   = 7;
  38.     public static final int NOTATION   = 8;
  39.     public static final int ENUMERATION= 9;
  40.     
  41.     String typeToString()
  42.     {                
  43.         switch(type)
  44.         {
  45.         case ID:
  46.             return "ID";
  47.         case IDREF:
  48.             return "IDREF";
  49.         case IDREFS:
  50.             return "IDREFS";
  51.         case ENTITY:
  52.             return "ENTITY";
  53.         case ENTITIES:
  54.             return "ENTITIES";
  55.         case NMTOKEN:
  56.             return "NMTOKEN";
  57.         case NMTOKENS:
  58.             return "NMTOKENS";
  59.         case NOTATION:
  60.             return "NOTATION";
  61.         case ENUMERATION:
  62.             return "ENUMERATION";
  63.         case CDATA:
  64.         default:
  65.             return "CDATA";
  66.         }
  67.     }
  68.  
  69.     /**
  70.      * presence of attribute
  71.      */    
  72.     public static final int DEFAULT    = 0;
  73.     public static final int REQUIRED   = 1;
  74.     public static final int IMPLIED    = 2;
  75.     public static final int FIXED      = 3;
  76.  
  77.     String presenceToString()
  78.     {
  79.         switch(presence)
  80.         {
  81.         case IMPLIED:
  82.             return "IMPLIED";
  83.         case REQUIRED:
  84.             return "REQUIRED";
  85.         case FIXED:
  86.             return "FIXED";
  87.         case DEFAULT:
  88.         default:
  89.             return "DEFAULT";
  90.         }               
  91.     }
  92.  
  93.     /**
  94.      * name of attribute declared
  95.      */
  96.     Name name;
  97.     
  98.     /**
  99.      * Construct new object for given attribute type.
  100.      * @param name the name of the attribute
  101.      * @param type the attribute type
  102.      */    
  103.     AttDef(Name name, int type)
  104.     {
  105.         this(name, type, null, 0, null);
  106.     }
  107.     
  108.     /**
  109.      * Construct new object for given attribute type and
  110.      * array of possible values.
  111.      */    
  112.     AttDef(Name name, int type, Vector values)
  113.     {
  114.         this(name, type, null, 0, values);
  115.     }
  116.     
  117.     /**
  118.      * Construct new object for given attribute type.
  119.      */    
  120.     AttDef(Name name, int type, Object def, int presence)
  121.     {
  122.         this(name, type, def, presence, null);
  123.     }
  124.     
  125.     /**
  126.      * Construct new object for given attribute type.
  127.      */    
  128.     AttDef(Name name, int type, Object def, int presence, Vector values)
  129.     {
  130.         this.name = name;
  131.         this.type = (byte)type;
  132.         this.def = def;
  133.         this.presence = (byte)presence;
  134.         this.values = values;
  135.     }
  136.  
  137.     /**
  138.      * Parse the attribute types.
  139.      */    
  140.     final Object parseAttribute(Element e, Parser parser) throws ParseException
  141.     {
  142.         parser.parseToken(Parser.QUOTE, "string");
  143.         return parseAttValue(e, parser, false);
  144.     }
  145.  
  146.     private void reportMismatch(Parser parser) throws ParseException
  147.     {
  148.         parser.error("Attribute " + name + " should have the fixed value \"" + def + "\"");
  149.     }
  150.  
  151.     private void reportEmpty(Parser parser, String s) throws ParseException
  152.     {
  153.         parser.error("Expected " + parser.tokenString(parser.NAME, s) + " insteadof " + parser.tokenString(parser.token, null));
  154.     }
  155.  
  156.     /**
  157.      *    parse attribute values
  158.      */
  159.     final Object parseAttValue(Element e, Parser parser, boolean inDTD) throws ParseException
  160.     {
  161.         int i;
  162.         Vector names;
  163.         Name name = null;
  164.         Object value;
  165.         StringBuffer buf;
  166.  
  167.         switch(type)
  168.         {
  169.         case CDATA:
  170.             parser.scanString(parser.quote, '&', '&', '<');
  171.             value = parser.text;
  172.             if (!inDTD && presence == FIXED && !def.toString().equals(parser.text))
  173.                 reportMismatch(parser);
  174.             break;
  175.         case ID:
  176.             parser.simplename++;
  177.             parser.parseToken(parser.NAME, "ID");
  178.             parser.simplename--;
  179.             parser.parseToken(parser.QUOTE, "string");
  180.             if (!inDTD)
  181.             {
  182.                 if (presence == FIXED && (Name)def != parser.name)
  183.                     reportMismatch(parser);
  184.                 Element e1 = parser.dtd.findID(parser.name);
  185.                 if (e1 != null)
  186.                 {
  187.                     parser.error("ID " + name + " is already used on element " + e1.getTagName());
  188.                 }
  189.                 parser.dtd.addID(parser.name, e);
  190.             }
  191.             value = parser.name;
  192.             break;
  193.         case IDREF:
  194.         case IDREFS:
  195.             names = new Vector();
  196.             buf = new StringBuffer();
  197.             parser.simplename++;
  198.             i = parser.parseNames(names, Parser.INVALIDTOKEN, buf);
  199.             parser.simplename--;
  200.             if (i == 0)
  201.                 reportEmpty(parser, "IDREF");
  202.             if (i > 1 && type == IDREF)
  203.                 parser.error("IDREF type attribute \"" + this.name + "\" cannot refer to more than one ID.");
  204.             if (!inDTD)
  205.             {
  206.                 for (--i; i >= 0; --i)
  207.                 {
  208.                     name = (Name)names.elementAt(i);
  209.                     if (presence == FIXED)
  210.                     {
  211.                         if (type == IDREFS)
  212.                             checkFixed(name, parser);
  213.                         else if ((Name)def != name) reportMismatch(parser);
  214.                     }
  215.                     if (parser.dtd.findID(name) == null)
  216.                     {
  217.                         // add it to linked list to check later
  218.                         parser.dtd.addIDCheck(name, 
  219.                             parser.reader.line, parser.reader.column - 1, 
  220.                             parser.reader.owner);
  221.                     }
  222.                 }
  223.             }          
  224.  
  225.             value = type == IDREF ? (Object)names.elementAt(0) : (Object)names;
  226.             break;
  227.         case ENTITY:
  228.         case ENTITIES:
  229.             buf = new StringBuffer();
  230.             names = new Vector();
  231.             parser.nouppercase++;
  232.             i = parser.parseNames(names, Parser.INVALIDTOKEN, buf);
  233.             parser.nouppercase--;
  234.             if (i == 0)
  235.                 reportEmpty(parser, "ENTITY name");
  236.              if (i > 1 && type == ENTITY) 
  237.                 parser.error("ENTITY type attribute \"" + this.name + "\" cannot refer to more than one entity.");
  238.             for (--i; i >= 0; --i)
  239.             {
  240.                 name = (Name)names.elementAt(i);
  241.                 if (parser.dtd.findEntity(name) == null)
  242.                 {
  243.                     parser.error("Couldn't find entity '" + name + "'");
  244.                 }
  245.                 if (!inDTD && presence == FIXED) 
  246.                 {
  247.                     if (type == ENTITIES)
  248.                         checkFixed(name, parser);
  249.                     else if (name != (Name)def) reportMismatch(parser);
  250.                 }
  251.             }
  252.  
  253.             value = type == ENTITY ? (Object)names.elementAt(0) : (Object)names;
  254.             break;
  255.         case NMTOKEN:
  256.         case NMTOKENS:
  257.             buf = new StringBuffer();
  258.             names = new Vector();
  259.             parser.nametoken++;
  260.             i = parser.parseNames(names, Parser.INVALIDTOKEN, buf);
  261.             parser.nametoken--;
  262.             if (i == 0)
  263.                 reportEmpty(parser, "NMTOKEN");
  264.             if (i > 1 && type == NMTOKEN)
  265.                 parser.error("NMTOKEN type attribute \"" + this.name + "\" cannot refer to more than one name token.");
  266.             if (!inDTD && presence == FIXED)
  267.             {
  268.                 if (type == NMTOKEN)
  269.                 {
  270.                     if ((Name)def != (Name)names.elementAt(0))
  271.                         reportMismatch(parser);
  272.                 }
  273.                 else 
  274.                 {
  275.                     for (i = names.size() - 1; i >= 0; i--)
  276.                     {
  277.                         checkFixed((Name)names.elementAt(i), parser);
  278.                     }
  279.                 }
  280.             }
  281.  
  282.             value = type == NMTOKEN ? (Object)names.elementAt(0) : (Object)names;
  283.             break;
  284.         case NOTATION:
  285.         case ENUMERATION:
  286.             if (type == ENUMERATION)
  287.                 parser.nametoken++;
  288.             parser.parseToken(parser.NAME, "name");
  289.             if (type == ENUMERATION)
  290.                 parser.nametoken--;
  291.             parser.parseToken(parser.QUOTE, "string");
  292.             for (i = values.size() - 1; i >= 0; i--)
  293.             {
  294.                 if ((Name)values.elementAt(i) == parser.name)
  295.                 {
  296.                     break;
  297.                 }
  298.             }
  299.             if (i < 0)
  300.             {
  301.                 parser.error("Attribute value '" + parser.name + "' is  not in the allowed set.");
  302.             }    
  303.             if (!inDTD && presence == FIXED && parser.name != def)
  304.                 reportMismatch(parser);
  305.  
  306.             value = parser.name;
  307.             break;
  308.         default:
  309.             value = null;
  310.         }
  311.         return value;
  312.     }
  313.  
  314.     private void checkFixed(Name name, Parser parser) throws ParseException
  315.     {
  316.         Vector v = (Vector)def;
  317.         int i;
  318.         for (i = v.size() - 1; i >= 0; i--)
  319.         {
  320.             if ((Name)v.elementAt(i) == name)
  321.             {
  322.                 break;
  323.             }
  324.         }
  325.         if (i < 0)
  326.         {
  327.             parser.error("Attribue value " + name + " is not in the fixed value set.");
  328.         }
  329.     }
  330.  
  331.     Element toSchema()
  332.     {
  333.         Element attribute = new ElementImpl( nameATTRIBUTE, Element.ELEMENT );
  334.         attribute.setAttribute( nameID, name.getName() );
  335.         attribute.setAttribute( nameTYPE, typeToString() );
  336.  
  337.         if( presence != DEFAULT )
  338.             attribute.setAttribute( namePRESENCE, presenceToString() );
  339.                 
  340.         if( type == ENUMERATION )
  341.         {
  342.             String valueString = "";
  343.             for (int i = 0; i < values.size(); i++) {   
  344.                 Name name = (Name)values.elementAt(i);
  345.                 valueString = valueString + name.toString();
  346.                 if (i < values.size() - 1)
  347.                     valueString = valueString + " ";
  348.             }
  349.             attribute.setAttribute( nameVALUES, valueString );
  350.         }
  351.  
  352.         if( def != null )
  353.             attribute.setAttribute( nameDEFAULT, def );
  354.  
  355.         return attribute;
  356.     }
  357.  
  358.     void save(Atom ns, XMLOutputStream o) throws IOException
  359.     {
  360.         if (name == Parser.nameXMLSpace)
  361.             o.writeChars(name.getName());
  362.         else
  363.             o.writeQualifiedName(name, ns);
  364.         switch(type)
  365.         {
  366.         case CDATA:
  367.             o.writeChars(" CDATA");
  368.             break;
  369.         case ID:
  370.             o.writeChars(" ID");
  371.             break;
  372.         case IDREF:
  373.             o.writeChars(" IDREF");
  374.             break;
  375.         case IDREFS:
  376.             o.writeChars(" IDREFS");
  377.             break;
  378.         case ENTITY:
  379.             o.writeChars(" ENTITY");
  380.             break;
  381.         case ENTITIES:
  382.             o.writeChars(" ENTITIES");
  383.             break;
  384.         case NMTOKEN:
  385.             o.writeChars(" NMTOKEN");
  386.             break;
  387.         case NMTOKENS:
  388.             o.writeChars(" NMTOKENS");
  389.             break;
  390.         case NOTATION:
  391.             o.writeChars(" NOTATION");
  392.             // fall through
  393.         case ENUMERATION:
  394.             o.writeChars(" (");
  395.             for (int i = 0; i < values.size(); i++) {   
  396.                 Name name = (Name)values.elementAt(i);
  397.                 if (type == NOTATION)
  398.                     o.writeQualifiedName(name, ns);
  399.                 else o.writeChars(name.toString());
  400.                 if (i < values.size() - 1)
  401.                     o.write('|');
  402.             }
  403.             o.write(')');
  404.             break;
  405.         }
  406.         switch (presence) {
  407.         case REQUIRED:
  408.             o.writeChars(" #REQUIRED");
  409.             break;
  410.         case IMPLIED:
  411.             o.writeChars(" #IMPLIED");
  412.             break;
  413.         case DEFAULT:
  414.         case FIXED:
  415.             if (presence == FIXED)
  416.                 o.writeChars(" #FIXED");
  417.             if (def != null) {
  418.                 o.writeChars(" ");
  419.                 switch (type)
  420.                 {
  421.                     case CDATA:
  422.                     case ID:
  423.                     case IDREF:
  424.                     case NMTOKEN:
  425.                     case ENUMERATION:
  426.                         o.writeQuotedString(def.toString());
  427.                         break;
  428.                     case NOTATION:
  429.                     case ENTITY:
  430.                         o.write('\"');
  431.                         o.writeQualifiedName((Name)def, ns);
  432.                         o.write('\"');
  433.                         break;
  434.                     case ENTITIES:
  435.                     case IDREFS:
  436.                     case NMTOKENS:
  437.                         o.write('\"');
  438.                         int i = 0;
  439.                         for (Enumeration e = ((Vector)def).elements(); e.hasMoreElements();)
  440.                         {
  441.                             if (i++ > 0)
  442.                                 o.write(Parser.OR);
  443.                             if (type == ENTITIES)
  444.                                 o.writeQualifiedName((Name)e.nextElement(), ns);
  445.                             else o.writeChars(e.nextElement().toString());
  446.                         }
  447.                         o.write('\"');
  448.                         break;
  449.                 }
  450.             }
  451.             break;
  452.         }
  453.     }
  454.    
  455.     byte type;    
  456.     byte presence;    
  457.     
  458.     /**
  459.      * default value, can be null
  460.      */    
  461.     Object def;
  462.     
  463.     /**
  464.      * array of values for enumerated and notation types
  465.      */    
  466.     Vector values;
  467.  
  468.     /**
  469.      * Return the default value for the attribute.
  470.      */    
  471.     public Object getDefault()
  472.     {
  473.         return def;
  474.     }
  475.  
  476.     /**
  477.      * Return the name of the attribute.
  478.      */
  479.     public Name getName()
  480.     {
  481.         return name;
  482.     }
  483.  
  484.     /** 
  485.      * Return the attribute type.
  486.      */
  487.     public int getType()
  488.     {
  489.         return (int)type;
  490.     }
  491.  
  492.     /**
  493.      * Return the precence type for the attribute.
  494.      */
  495.     public int getPresence()
  496.     {
  497.         return (int)presence;
  498.     }
  499.  
  500.     static Name nameATTRIBUTE = Name.create("ATTRIBUTE","XML");
  501.     static Name nameID        = Name.create("ID","XML");
  502.     static Name nameDEFAULT   = Name.create("DEFAULT","XML");
  503.     static Name namePRESENCE  = Name.create("PRESENCE","XML");
  504.     static Name nameVALUES    = Name.create("VALUES","XML");
  505.     static Name nameTYPE      = Name.create("TYPE","XML");
  506. }    
  507.