/// <summary> /// Index an element. This finds the parents for all elements. /// </summary> /// <param name="parentElement">The parent element of the element to index.</param> /// <param name="element">The element to index.</param> private void IndexElement(XmlSchemaElement parentElement, XmlSchemaElement element) { XmlSchemaElementInfo elementInfo = (XmlSchemaElementInfo)this.elements[element.QualifiedName]; if (elementInfo == null) { elementInfo = new XmlSchemaElementInfo(); this.elements.Add(element.QualifiedName, elementInfo); } // index the parent if (parentElement != null) { elementInfo.AddParent(parentElement.QualifiedName); } // do not index an element if it has already been indexed if (!elementInfo.Indexed) { // retrieve the real element (not just a reference to it) if (element.QualifiedName.Namespace != null) { element = (XmlSchemaElement)this.schemas[element.QualifiedName.Namespace].Elements[element.QualifiedName]; } // mark the element as indexed early in case it references itself elementInfo.Indexed = true; // retrieve explicitly-specified parent elements if (element.Annotation != null) { foreach (XmlSchemaObject obj in element.Annotation.Items) { XmlSchemaAppInfo appInfo = obj as XmlSchemaAppInfo; if (appInfo != null) { foreach (XmlNode node in appInfo.Markup) { XmlElement markupElement = node as XmlElement; if (markupElement != null && markupElement.LocalName == "parent" && markupElement.NamespaceURI == XmlSchemaExtensionNamespace) { string parentNamespace = markupElement.GetAttribute("namespace"); string parentRef = markupElement.GetAttribute("ref"); if (parentNamespace.Length == 0) { throw new ApplicationException("The parent element is missing the namespace attribute."); } if (parentRef.Length == 0) { throw new ApplicationException("The parent element is missing the ref attribute."); } XmlQualifiedName parentQualifiedName = new XmlQualifiedName(parentRef, parentNamespace); // add the explicit parent to the list of parents for this element elementInfo.AddParent(parentQualifiedName); // add this element to the extended list of children for its parent XmlSchemaElementInfo parentElementInfo = (XmlSchemaElementInfo)this.elements[parentQualifiedName]; if (parentElementInfo == null) { parentElementInfo = new XmlSchemaElementInfo(); this.elements.Add(parentQualifiedName, parentElementInfo); } parentElementInfo.AddExtendedChild(element.QualifiedName); } } } } } if (element.ElementType is XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType)element.ElementType; if (complexType.Particle != null) { this.IndexParticle(element, complexType.Particle); } } } }
/// <summary> /// Write the particle. /// </summary> /// <param name="ownerElementInfo">Extra information about the owner element.</param> /// <param name="parentParticle">The parent of the particle being written.</param> /// <param name="particle">The particle.</param> /// <param name="writer">The html writer.</param> private void WriteParticle(XmlSchemaElementInfo ownerElementInfo, XmlSchemaParticle parentParticle, XmlSchemaParticle particle, XmlWriter writer) { if (particle is XmlSchemaAny) { XmlSchemaAny any = (XmlSchemaAny)particle; writer.WriteStartElement("span"); writer.WriteAttributeString("class", "extension"); writer.WriteString(String.Format("Any Element (namespace='{0}' processContents='{1}')", any.Namespace, any.ProcessContents.ToString())); string description = GetDescription(any); if (!String.IsNullOrEmpty(description)) { writer.WriteString(" "); writer.WriteRaw(description); } writer.WriteEndElement(); // TODO: Ideally, we wouldn't include children that are already listed directly. To handle // this, we'd have to keep track of all child elements we've already written (directly // or indirectly), and check the list for each of the ExtendedChildren we process. if (ownerElementInfo.ExtendedChildren.Count > 0) { writer.WriteStartElement("ul"); foreach (XmlQualifiedName childQualifiedName in ownerElementInfo.ExtendedChildren) { writer.WriteStartElement("li"); this.WriteElementLink(childQualifiedName, writer); writer.WriteEndElement(); } writer.WriteEndElement(); } } else if (particle is XmlSchemaChoice) { XmlSchemaChoice choice = (XmlSchemaChoice)particle; // sort element children SortedList children = new SortedList(); foreach (XmlSchemaParticle childParticle in choice.Items) { if (childParticle is XmlSchemaElement) { children.Add(((XmlSchemaElement)childParticle).QualifiedName.Name, childParticle); } else if (childParticle is XmlSchemaAny) { children.Add("ZZZ", childParticle); } else // sort non-element children by their line number { children.Add(String.Concat("Z", childParticle.LineNumber.ToString(CultureInfo.InvariantCulture)), childParticle); } } writer.WriteString(String.Format("Choice of elements (min: {0}, max: {1})", (choice.MinOccurs == Decimal.MaxValue ? "unbounded" : choice.MinOccurs.ToString(CultureInfo.InvariantCulture)), (choice.MaxOccurs == Decimal.MaxValue ? "unbounded" : choice.MaxOccurs.ToString(CultureInfo.InvariantCulture)))); writer.WriteStartElement("ul"); foreach (XmlSchemaParticle childParticle in children.Values) { writer.WriteStartElement("li"); this.WriteParticle(ownerElementInfo, particle, childParticle, writer); writer.WriteEndElement(); } writer.WriteEndElement(); } else if (particle is XmlSchemaElement) { XmlSchemaElement element = (XmlSchemaElement)particle; this.WriteElementLink(element.QualifiedName, writer); writer.WriteString(" (min: "); if (element.MinOccursString != null) { writer.WriteString(element.MinOccursString); } else if (parentParticle != null) { if (parentParticle.MinOccursString != null) { writer.WriteString(parentParticle.MinOccursString); } else { writer.WriteString(parentParticle.MinOccurs.ToString(CultureInfo.InvariantCulture)); } } writer.WriteString(", max: "); if (element.MaxOccursString != null) { writer.WriteString(element.MaxOccursString); } else if (parentParticle != null) { if (parentParticle.MaxOccursString != null) { writer.WriteString(parentParticle.MaxOccursString); } else { writer.WriteString(parentParticle.MaxOccurs.ToString(CultureInfo.InvariantCulture)); } } writer.WriteString(")"); string description = GetDescription(element); if (description != null && description.Length > 0) { writer.WriteString(": "); writer.WriteRaw(htmlPrefix.Replace(description.Trim().Replace("\t", String.Empty).Replace(Environment.NewLine, " "), String.Empty)); } } else if (particle is XmlSchemaSequence) { XmlSchemaSequence sequence = (XmlSchemaSequence)particle; writer.WriteString(String.Format("Sequence (min: {0}, max: {1})", (sequence.MinOccurs == Decimal.MaxValue ? "unbounded" : sequence.MinOccurs.ToString(CultureInfo.InvariantCulture)), (sequence.MaxOccurs == Decimal.MaxValue ? "unbounded" : sequence.MaxOccurs.ToString(CultureInfo.InvariantCulture)))); writer.WriteStartElement("ol"); foreach (XmlSchemaParticle childParticle in sequence.Items) { writer.WriteStartElement("li"); this.WriteParticle(ownerElementInfo, particle, childParticle, writer); writer.WriteEndElement(); } writer.WriteEndElement(); } else if (particle is XmlSchemaGroupRef) { // Document the group's children as particles of our parent. XmlSchemaGroupRef groupRef = (XmlSchemaGroupRef)particle; this.WriteParticle(ownerElementInfo, particle, groupRef.Particle, writer); } else { throw new ApplicationException(String.Format("Unknown particle type: {0}.", particle.GetType().ToString())); } }
/// <summary> /// Write the documentation file for an element. /// </summary> /// <param name="schema">The parent schema of the element.</param> /// <param name="element">The element.</param> /// <param name="elementInfo">Extra information about the element.</param> private void WriteElementDoc(XmlSchema schema, XmlSchemaElement element, XmlSchemaElementInfo elementInfo) { StringBuilder content; using (XmlWriter writer = CreateXmlWriter(out content)) { writer.WriteStartElement("dl"); this.WriteDescription(element, writer); this.WriteWIReferences(element, writer); this.WriteParents(elementInfo.Parents, writer); this.WriteInnerText(element, writer); this.WriteChildren(element, writer); this.WriteAttributes(element, writer); this.WriteRemarks(element, writer); this.WriteHowTos(schema, element, writer); this.WriteSeeAlso(schema, element, writer); writer.WriteEndElement(); } string mdFile = this.GetSchemaMarkdownFile(schema, element.Name); string layout = (this.mainSchemas.Contains(schema) ? MainLayout : ExtensionLayout); WriteContentFile(mdFile, this.GetTitleWithExtension(element.Name, "Element", schema), layout, content); }
/// <summary> /// Write the documentation file for an element. /// </summary> /// <param name="schema">The parent schema of the element.</param> /// <param name="element">The element.</param> /// <param name="elementInfo">Extra information about the element.</param> private void WriteElementDoc(XmlSchema schema, XmlSchemaElement element, XmlSchemaElementInfo elementInfo) { string htmlFile = this.GetSchemaHtmlFile(schema, element.Name); XmlTextWriter writer = null; try { string headerClass = (schema == this.mainSchema ? "elementHeader" : "extensionHeader"); writer = StartHtmlWriter(htmlFile, String.Concat(element.Name, " Element"), headerClass); writer.WriteStartElement("dl"); this.WriteDescription(element, writer); this.WriteWIReferences(element, writer); this.WriteParents(elementInfo.Parents, writer); this.WriteInnerText(element, writer); this.WriteChildren(element, writer); this.WriteAttributes(element, writer); this.WriteRemarks(element, writer); this.WriteSeeAlso(schema, element, writer); // only write the version number if it is set if (this.versionNumber != null) { this.WriteVersion(writer); } writer.WriteEndElement(); EndHtmlWriter(writer); } finally { if (writer != null) { writer.Close(); } } }
/// <summary> /// Write the particle. /// </summary> /// <param name="ownerElementInfo">Extra information about the owner element.</param> /// <param name="parentParticle">The parent of the particle being written.</param> /// <param name="particle">The particle.</param> /// <param name="writer">The html writer.</param> private void WriteParticle(XmlSchemaElementInfo ownerElementInfo, XmlSchemaParticle parentParticle, XmlSchemaParticle particle, XmlTextWriter writer) { if (particle is XmlSchemaAny) { XmlSchemaAny any = (XmlSchemaAny)particle; writer.WriteStartElement("span"); writer.WriteAttributeString("class", "extension"); writer.WriteString(String.Format("Any Element namespace='{0}' processContents='{1}'", any.Namespace, any.ProcessContents.ToString())); writer.WriteEndElement(); if (ownerElementInfo.ExtendedChildren.Count > 0) { writer.WriteStartElement("ul"); foreach (XmlQualifiedName childQualifiedName in ownerElementInfo.ExtendedChildren) { writer.WriteStartElement("li"); this.WriteElementLink(childQualifiedName, writer); writer.WriteEndElement(); } writer.WriteEndElement(); } } else if (particle is XmlSchemaChoice) { XmlSchemaChoice choice = (XmlSchemaChoice)particle; // sort element children SortedList children = new SortedList(); foreach (XmlSchemaParticle childParticle in choice.Items) { if (childParticle is XmlSchemaElement) { children.Add(((XmlSchemaElement)childParticle).QualifiedName.Name, childParticle); } else if (childParticle is XmlSchemaAny) { children.Add("ZZZ", childParticle); } else // sort non-element children by their line number { children.Add(String.Concat("Z", childParticle.LineNumber.ToString(CultureInfo.InvariantCulture)), childParticle); } } writer.WriteString(String.Format("Choice of elements (min: {0}, max: {1})", (choice.MinOccurs == Decimal.MaxValue ? "unbounded" : choice.MinOccurs.ToString(CultureInfo.InvariantCulture)), (choice.MaxOccurs == Decimal.MaxValue ? "unbounded" : choice.MaxOccurs.ToString(CultureInfo.InvariantCulture)))); writer.WriteStartElement("ul"); foreach (XmlSchemaParticle childParticle in children.Values) { writer.WriteStartElement("li"); this.WriteParticle(ownerElementInfo, particle, childParticle, writer); writer.WriteEndElement(); } writer.WriteEndElement(); } else if (particle is XmlSchemaElement) { XmlSchemaElement element = (XmlSchemaElement)particle; this.WriteElementLink(element.QualifiedName, writer); writer.WriteString(" (min: "); if (element.MinOccursString != null) { writer.WriteString(element.MinOccursString); } else if (parentParticle != null) { if (parentParticle.MinOccursString != null) { writer.WriteString(parentParticle.MinOccursString); } else { writer.WriteString(parentParticle.MinOccurs.ToString(CultureInfo.InvariantCulture)); } } writer.WriteString(", max: "); if (element.MaxOccursString != null) { writer.WriteString(element.MaxOccursString); } else if (parentParticle != null) { if (parentParticle.MaxOccursString != null) { writer.WriteString(parentParticle.MaxOccursString); } else { writer.WriteString(parentParticle.MaxOccurs.ToString(CultureInfo.InvariantCulture)); } } writer.WriteString(")"); string description = GetDescription(element); if (description != null && description.Length > 0) { writer.WriteString(": "); writer.WriteString(description); } } else if (particle is XmlSchemaSequence) { XmlSchemaSequence sequence = (XmlSchemaSequence)particle; writer.WriteString(String.Format("Sequence (min: {0}, max: {1})", (sequence.MinOccurs == Decimal.MaxValue ? "unbounded" : sequence.MinOccurs.ToString(CultureInfo.InvariantCulture)), (sequence.MaxOccurs == Decimal.MaxValue ? "unbounded" : sequence.MaxOccurs.ToString(CultureInfo.InvariantCulture)))); writer.WriteStartElement("ol"); foreach (XmlSchemaParticle childParticle in sequence.Items) { writer.WriteStartElement("li"); this.WriteParticle(ownerElementInfo, particle, childParticle, writer); writer.WriteEndElement(); } writer.WriteEndElement(); } else { throw new ApplicationException(String.Format("Unknown particle type: {0}.", particle.GetType().ToString())); } }
/// <summary> /// Write the documentation file for an element. /// </summary> /// <param name="schema">The parent schema of the element.</param> /// <param name="element">The element.</param> /// <param name="elementInfo">Extra information about the element.</param> private void WriteElementDoc(XmlSchema schema, XmlSchemaElement element, XmlSchemaElementInfo elementInfo) { string htmlFile = this.GetSchemaHtmlFile(schema, element.Name); XmlTextWriter writer = null; try { string headerClass = (this.mainSchemas.Contains(schema) ? "elementHeader" : "extensionHeader"); writer = StartHtmlWriter(htmlFile, this.GetTitleWithExtension(element.Name, "Element", schema), headerClass); writer.WriteStartElement("dl"); this.WriteDescription(element, writer); this.WriteWIReferences(element, writer); this.WriteParents(elementInfo.Parents, writer); this.WriteInnerText(element, writer); this.WriteChildren(element, writer); this.WriteAttributes(element, writer); this.WriteRemarks(element, writer); this.WriteHowTos(schema, element, writer); this.WriteSeeAlso(schema, element, writer); writer.WriteEndElement(); this.WriteVersion(writer); EndHtmlWriter(writer); } finally { if (writer != null) { writer.Close(); } } }