internal ElementTypeRef IsValidSequence(ElementType et, ICollection s, int index) { ICollection col=et.ContentModel.GetValidFirstElements(); int count=0; ElementTypeRef ret=null; foreach ( XmlName name in s ) { count++; if ( !et.HasChildElement(name) ) // ignore elements that simply aren't in the model // TODO: H: count can get out continue; ElementTypeRef sr=FindInCollection(col, name); if ( count == index+1 ) { ret=sr; } if ( sr == null ) { // element name is not allowed here if ( ret != null && count < index+1 ) return ret; return null; } // TODO: M: optimise - this is called at end of s even though not going to loop again col=sr.OriginalReference.GetValidNextElements(); } // TODO: M: think about required elements at end - but probably // not needed here because don't want to stop someone // adding an element even if more are allowed return ret; }
public void Validate(XmlElement e, ElementType et, ICollection list) { switch ( et.ContentType ) { case ElementContentType.Any: ValidateAnyModel(); break; case ElementContentType.Element: ValidateElementModel(e, et, list); break; case ElementContentType.Empty: ValidateEmptyModel(list); break; case ElementContentType.Mixed: ValidateMixedModel(et, list); break; case ElementContentType.PCDATA: ValidateTextModel(list); break; } }
internal bool IsValid(ElementType et, ICollection list) { switch ( et.ContentType ) { case ElementContentType.Any: return true; case ElementContentType.Element: return IsValidElementContent(et, list); case ElementContentType.Empty: // TODO: H: too simplistic return list.Count == 0; case ElementContentType.Mixed: return IsValidMixedContent(et, list); case ElementContentType.PCDATA: return IsValidTextContent(et, list); default: // can never happen due to enum throw new InvalidOperationException("Unrecognised ElementContentType enum"); } }
public void AddChildElement(ElementType child) { if ( children[child.Name] == null ) children.Add(child.Name, child); }
void getMixedContent(ElementType parent) { bool moreNames = true; discardWhitespace(); requireString("PCDATA"); discardWhitespace(); if (isChar('|')) { // Content model is mixed: (#PCDATA | A | B)* parent.ContentType = ElementContentType.Mixed; // Add a choice Group for the content model. parent.ContentModel = new ContentModel(); parent.ContentModel.Type = ParticleType.Choice; parent.ContentModel.IsRequired = false; parent.ContentModel.IsRepeatable = true; // Process the element type names. There must be at least one, // or we would have fallen into the else clause below. while (moreNames) { discardWhitespace(); getReference(parent.ContentModel, parent, true); discardWhitespace(); moreNames = isChar('|'); } // Close the content model. requireString(")*"); } else { // Content model is PCDATA-only: (#PCDATA) parent.ContentType = ElementContentType.PCDATA; requireChar(')'); // 5/17/00, Ronald Bourret // Check if there is an asterisk after the closing parenthesis. // This covers the following case: // <!ELEMENT A (#PCDATA)*> isChar('*'); } }
private bool IsValidMixedContent(ElementType et, ICollection list) { // list is assumed to contain all children (including indirect children via entity reference) foreach ( XmlNode n in list ) { XmlElement e=n as XmlElement; if ( e == null ) continue; bool valid=false; foreach ( ElementType ct in et.ChildElements ) { if ( ct.Name.QualifiedName.Equals(n.Name) ) { valid=true; break; } } if ( !valid ) return false; } return true; }
private void ValidateElementModel(XmlElement e, ElementType et, ICollection children) { ICollection col=et.ContentModel.GetValidFirstElements(); bool elementMissing=false; foreach ( XmlNode n in children ) { client.StartChildValidation(n); if ( n.NodeType == XmlNodeType.Text ) { client.ProcessError(n, ValidationErrorType.NodeNotAllowed); } else if ( n.NodeType == XmlNodeType.Element ) { ElementType et2=documentType.GetElementType((XmlElement) n); if ( et2 == null ) // not in DTD, will be picked up later continue; // TODO: E: entities! if ( !et.HasChildElement(new XmlName(n)) ) { // this element can never be allowed here client.ProcessError(n, ValidationErrorType.ElementNotInContentModel); continue; } if ( elementMissing ) continue; ElementTypeRef sr=FindInCollection(col, (XmlElement) n); if ( sr == null ) { foreach ( ElementTypeRef etr in col ) { if ( etr.IsRequired ) { elementMissing=true; client.ProcessError(n, ValidationErrorType.ElementNotAllowedHere); break; } } if ( elementMissing ) continue; client.ProcessError(n, ValidationErrorType.NodeNotAllowed); } else col=sr.OriginalReference.GetValidNextElements(); } } if ( !elementMissing ) { foreach ( ElementTypeRef sr in col ) { if ( sr.IsRequired ) { // TODO: M: can provide some more info to the error here client.ProcessError(e, ValidationErrorType.RequiredElementMissing); break; } } } }
Attribute getAttribute(ElementType elementType) { XmlName name; Attribute attribute; // Get the attribute name and create a new Attribute. name = getXMLName(); attribute = new Attribute(name); // If the element does not have an attribute with this name, add // it to the ElementType. Otherwise, ignore it. elementType.AddAttribute(attribute); // Return the new Attribute. Note that we do this even if it is // not added to the ElementType so that other code is simpler. return attribute; }
void getContentModel(ElementType elementType) { // Get the content model. if (isChar('(')) { // 5/18/00, Ronald Bourret // Added following call to discardWhitespace(). This is needed // for the case where space precedes the '#': // <!ELEMENT A ( #PCDATA | B )*> discardWhitespace(); if (isChar('#')) { getMixedContent(elementType); } else { getElementContent(elementType); } } else if (isString("EMPTY")) { elementType.ContentType = ElementContentType.Empty; } else if (isString("ANY")) { elementType.ContentType = ElementContentType.Any; } else throwXMLMiddlewareException("Invalid element type declaration."); }
Reference getReference(Group group, ElementType parent, bool mixed) { // XMLName name; ElementType child; Reference rf; // Create an ElementType for the referenced child. child = createElementType(); // Add the child to the parent and vice versa. If we are processing // mixed content, then each child must be unique in the parent. if ( mixed ) { if (parent.HasChildElement(child.Name)) throwXMLMiddlewareException("The element type " + child.Name + " appeared more than once in the declaration of mixed content for the element type " + parent.Name + "."); } parent.AddChildElement(child); child.AddParentElement(parent); // Create a Reference for the child, add it to the group, and return it. rf = new Reference(child); group.AddMember(rf); return rf; }
void getAttDef(ElementType elementType) { // S already parsed. Attribute attribute; attribute = getAttribute(elementType); requireWhitespace(); getAttributeType(attribute); requireWhitespace(); getAttributeRequired(attribute); }
internal Style GetStyle(IGraphics gr, Style parentStyle, XmlElement e, ElementType et) { Style ret=parentStyle == null ? blockStyle : parentStyle; bool foundMatch=false; foreach ( Style s in Styles ) { if ( s.IsMatch(e.CreateNavigator(), nsMgr) ) { ret=Cascade(gr, ret, s); foundMatch=true; } } bool emptyModel=et != null && et.ContentType == ElementContentType.Empty; if ( !foundMatch ) { // TODO: M: could optimise this perhaps XmlElement parent=e.ParentNode as XmlElement; if ( parent == null ) ret=Cascade(gr, ret, new BlockStyle()); else if ( HasText(parent) || emptyModel ) ret=Cascade(gr, ret, new InlineStyle()); else ret=Cascade(gr, ret, new BlockStyle()); } if ( e.HasChildNodes ) // if element has child nodes, it cannot be shown as empty ret.Empty=false; else if ( emptyModel ) // empty element in DTD so flag as such ret.Empty=true; return ret; }
internal Style GetStyle(IGraphics gr, XmlElement e, ElementType et) { return GetStyle(gr, null, e, et); }
public void AddParentElement(ElementType parent) { if ( parents[parent.Name] == null ) parents.Add(parent.Name, parent); }
private ElementListItem[] FindValidElements(ElementType et, XmlElement parent, XmlNode n, bool replace) { int index=-1; ArrayList children=new ArrayList(); foreach ( XmlNode c in parent.ChildNodes ) { if ( c.Equals(n) ) index=children.Count; if ( c.NodeType != XmlNodeType.Element ) continue; XmlName xn=new XmlName(c); children.Add(xn); } if ( index < 0 ) { Debug.Assert(!replace, "This can't happen if in replace mode"); children.Add(null); index=children.Count-1; } else { if ( !replace ) children.Insert(index, null); } ArrayList ret=new ArrayList(); foreach ( ElementType t in et.ChildElements ) { children[index]=t.Name; ElementTypeRef sr=IsValidSequence(et, children, index); if ( sr != null ) ret.Add(new ElementListItem(sr.Name, sr.IsRequired, sr.IsChoice)); } return ret.ToArray(typeof(ElementListItem)) as ElementListItem[]; }
void getContentParticle(Group group, ElementType parent) { Group childGroup; Reference rf; if (isChar('(')) { childGroup = new Group(); group.AddMember(childGroup); getGroup(childGroup, parent); } else { rf = getReference(group, parent, false); getFrequency(rf); } }
private bool IsValidElementContent(ElementType et, ICollection list) { // list is assumed to contain all children (including indirect children via entity reference) ICollection col=et.ContentModel.GetValidFirstElements(); foreach ( XmlNode n in list ) { if ( XmlUtil.IsTextContent(n) ) return false; XmlElement e=n as XmlElement; if ( e == null ) // not significant, eg. comment continue; ElementTypeRef sr=FindInCollection(col, new XmlName(e)); if ( sr == null ) return false; col=sr.OriginalReference.GetValidNextElements(); } // TODO: think about required elements (remaining col) return true; }
void getElementContent(ElementType elementType) { elementType.ContentModel = new ContentModel(); elementType.ContentType = ElementContentType.Element; getGroup(elementType.ContentModel, elementType); elementType.ContentModel.FinaliseGroup(); }
private bool IsValidTextContent(ElementType et, ICollection list) { foreach ( XmlNode n in list ) { XmlElement e=n as XmlElement; // TODO: E: entities if ( e != null ) return false; } return true; }
void getGroup(Group group, ElementType parent) { // This gets a choice or sequence. bool moreCPs = true; while (moreCPs) { discardWhitespace(); getContentParticle(group, parent); discardWhitespace(); if (isChar('|')) { if (group.Type == ParticleType.Unknown) { group.Type = ParticleType.Choice; } else if (group.Type == ParticleType.Sequence) { throwXMLMiddlewareException("Invalid mixture of ',' and '|' in content model."); } } else if (isChar(',')) { if (group.Type == ParticleType.Unknown) { group.Type = ParticleType.Sequence; } else if (group.Type == ParticleType.Choice) { throwXMLMiddlewareException("Invalid mixture of ',' and '|' in content model."); } } else if (isChar(')')) { moreCPs = false; getFrequency(group); // If there is a single content particle in the group, // we simply call it a sequence. if (group.Type == ParticleType.Unknown) { group.Type = ParticleType.Sequence; } } } group.FinaliseGroup(); }
private void ValidateMixedModel(ElementType et, ICollection list) { foreach ( XmlNode n in list ) { client.StartChildValidation(n); if ( n.NodeType != XmlNodeType.Element ) // TODO: H: entities! continue; // { // RemoveValidationErrors(n); // continue; // } if ( !et.HasChildElement(new XmlName(n.Name)) ) client.ProcessError(n, ValidationErrorType.ElementNotInContentModel); } }
/** * Create an ElementType by XMLName. * * <p>If the ElementType already exists, it is returned. Otherwise, a new * ElementType is created.</p> * * @param name The XMLName of the element type. * @return The ElementType. */ public ElementType CreateElementType(XmlName name) { // Get an existing ElementType or add a new one if it doesn't exist. // // This method exists because we frequently need to refer to an // ElementType object before it is formally created. For example, if // element type A is defined before element type B, and the content model // of element type A contains element type B, we need to add the // ElementType object for B (as a reference in the content model of A) // before it is formally defined and created. ElementType elementType; elementType = (ElementType)elementTypes[name]; if (elementType == null) { elementType = new ElementType(name); elementTypes[name]=elementType; } return elementType; }