private void DocumentFunction(XmlElement functionElement, NAntXsltUtilities utilities) { if (functionElement == null) { throw new ArgumentNullException("functionElement"); } string methodID = functionElement.GetAttribute("id"); string filename = utilities.GetFileNameForFunction(functionElement, false); XsltArgumentList arguments = CreateXsltArgumentList(); arguments.AddParam("method-id", string.Empty, methodID); arguments.AddParam("refType", string.Empty, "Function"); arguments.AddParam("functionName", string.Empty, functionElement.GetAttribute("name")); // add extension object to Xslt arguments arguments.AddExtensionObject("urn:NAntUtil", utilities); // document parameter types foreach (XmlAttribute paramTypeAttribute in functionElement.SelectNodes("parameter/@type")) { string paramType = "T:" + paramTypeAttribute.Value; XmlNode typeNode = utilities.GetTypeNodeByID(paramType); if (typeNode != null) { ElementDocType paramDocType = utilities.GetElementDocType(typeNode); if (paramDocType != ElementDocType.None) { DocumentType(typeNode, paramDocType, utilities); } } } // document return type XmlAttribute returnTypeAttribute = functionElement.Attributes["returnType"]; if (returnTypeAttribute != null) { string returnType = "T:" + returnTypeAttribute.Value; XmlNode returnTypeNode = utilities.GetTypeNodeByID(returnType); if (returnTypeNode != null) { ElementDocType returnDocType = utilities.GetElementDocType(returnTypeNode); if (returnDocType != ElementDocType.None) { DocumentType(returnTypeNode, returnDocType, utilities); } } } // create the page TransformAndWriteResult(_xsltFunctionDoc, arguments, filename); }
private void DocumentType(XmlNode typeNode, ElementDocType docType, NAntXsltUtilities utilities) { if (typeNode == null) { throw new ArgumentNullException("typeNode"); } if (docType == ElementDocType.None || docType == ElementDocType.FunctionSet) { // we don't need to document this type return; } string classID = typeNode.Attributes["id"].Value; if (!classID.Substring(2).StartsWith(NamespaceFilter)) { // we don't need to types in this namespace return; } string filename = utilities.GetFileNameForType(typeNode, false); if (filename == null) { // we should never get here, but just in case ... return; } if (_writtenFiles.ContainsValue(classID)) { return; } else { _writtenFiles.Add(filename, classID); } // create arguments for nant task page transform (valid args are class-id, refType, imagePath, relPathAdjust) XsltArgumentList arguments = CreateXsltArgumentList(); arguments.AddParam("class-id", String.Empty, classID); string refTypeString; switch (docType) { case ElementDocType.DataTypeElement: refTypeString = "Type"; break; case ElementDocType.Element: refTypeString = "Element"; break; case ElementDocType.Task: refTypeString = "Task"; break; case ElementDocType.Enum: refTypeString = "Enum"; break; case ElementDocType.Filter: refTypeString = "Filter"; break; default: refTypeString = "Other?"; break; } arguments.AddParam("refType", string.Empty, refTypeString); // add extension object to Xslt arguments arguments.AddExtensionObject("urn:NAntUtil", utilities); // Process all sub-elements and generate docs for them. :) // Just look for properties with attributes to narrow down the foreach loop. // (This is a restriction of NAnt.Core.Attributes.BuildElementAttribute) foreach (XmlNode propertyNode in typeNode.SelectNodes("property[attribute]")) { //get the xml element string elementName = utilities.GetElementNameForProperty(propertyNode); if (elementName != null) { // try to get attribute info if it is an array/collection. // strip the array brakets "[]" to get the type string elementType = "T:" + propertyNode.Attributes["type"].Value.Replace("[]",""); // check whether property is an element array XmlNode nestedElementNode = propertyNode.SelectSingleNode("attribute[@name='" + typeof(BuildElementArrayAttribute).FullName + "']"); if (nestedElementNode == null) { // check whether property is an element collection nestedElementNode = propertyNode.SelectSingleNode("attribute[@name='" + typeof(BuildElementCollectionAttribute).FullName + "']"); } // if property is either array or collection type element if (nestedElementNode != null) { // select the item type in the collection XmlAttribute elementTypeAttribute = _xmlDocumentation.SelectSingleNode("//class[@id='" + elementType + "']/method[@name='Add']/parameter/@type") as XmlAttribute; if (elementTypeAttribute != null) { // get type of collection elements elementType = "T:" + elementTypeAttribute.Value; } // if it contains a ElementType attribute then it is an array or collection // if it is a collection, then we care about the child type. XmlNode explicitElementType = propertyNode.SelectSingleNode("attribute/property[@ElementType]"); if (explicitElementType != null) { // ndoc is inconsistent about how classes are named. elementType = explicitElementType.Attributes["value"].Value.Replace("+","."); } } XmlNode elementTypeNode = utilities.GetTypeNodeByID(elementType); if (elementTypeNode != null) { ElementDocType elementDocType = utilities.GetElementDocType(elementTypeNode); if (elementDocType != ElementDocType.None) { DocumentType(elementTypeNode, elementDocType, utilities); } } } } // create the page TransformAndWriteResult(_xsltTypeDoc, arguments, filename); }
private void DocumentType(XmlNode typeNode, ElementDocType docType, NAntXsltUtilities utilities) { if (typeNode == null) { throw new ArgumentNullException("typeNode"); } if (docType == ElementDocType.None || docType == ElementDocType.FunctionSet) { // we don't need to document this type return; } string classID = typeNode.Attributes["id"].Value; if (!classID.Substring(2).StartsWith(NamespaceFilter)) { // we don't need to types in this namespace return; } string filename = utilities.GetFileNameForType(typeNode); if (filename == null) { // we should never get here, but just in case ... return; } if (_writtenFiles.ContainsValue(classID)) { return; } else { _writtenFiles.Add(filename, classID); } // create arguments for nant task page transform (valid args are class-id, refType, imagePath, relPathAdjust) XsltArgumentList arguments = CreateXsltArgumentList(); arguments.AddParam("class-id", String.Empty, classID); string refTypeString; switch (docType) { case ElementDocType.DataTypeElement: refTypeString = "Type"; break; case ElementDocType.Element: refTypeString = "Element"; break; case ElementDocType.Task: refTypeString = "Task"; break; case ElementDocType.Enum: refTypeString = "Enum"; break; case ElementDocType.Filter: refTypeString = "Filter"; break; default: refTypeString = "Other?"; break; } arguments.AddParam("refType", string.Empty, refTypeString); // add extension object to Xslt arguments arguments.AddExtensionObject("urn:NAntUtil", utilities); // Process all sub-elements and generate docs for them. :) // Just look for properties with attributes to narrow down the foreach loop. // (This is a restriction of NAnt.Core.Attributes.BuildElementAttribute) foreach (XmlNode propertyNode in typeNode.SelectNodes("property[attribute]")) { //get the xml element string elementName = utilities.GetElementNameForProperty(propertyNode); if (elementName != null) { // try to get attribute info if it is an array/collection. // strip the array brakets "[]" to get the type string elementType = "T:" + propertyNode.Attributes["type"].Value.Replace("[]", ""); // check whether property is an element array XmlNode nestedElementNode = propertyNode.SelectSingleNode("attribute[@name='" + typeof(BuildElementArrayAttribute).FullName + "']"); if (nestedElementNode == null) { // check whether property is an element collection nestedElementNode = propertyNode.SelectSingleNode("attribute[@name='" + typeof(BuildElementCollectionAttribute).FullName + "']"); } // if property is either array or collection type element if (nestedElementNode != null) { // select the item type in the collection XmlAttribute elementTypeAttribute = _xmlDocumentation.SelectSingleNode("//class[@id='" + elementType + "']/method[@name='Add']/parameter/@type") as XmlAttribute; if (elementTypeAttribute != null) { // get type of collection elements elementType = "T:" + elementTypeAttribute.Value; } // if it contains a ElementType attribute then it is an array or collection // if it is a collection, then we care about the child type. XmlNode explicitElementType = propertyNode.SelectSingleNode("attribute/property[@ElementType]"); if (explicitElementType != null) { // ndoc is inconsistent about how classes are named. elementType = explicitElementType.Attributes["value"].Value.Replace("+", "."); } } XmlNode elementTypeNode = utilities.GetTypeNodeByID(elementType); if (elementTypeNode != null) { ElementDocType elementDocType = utilities.GetElementDocType(elementTypeNode); if (elementDocType != ElementDocType.None) { DocumentType(elementTypeNode, elementDocType, utilities); } } } } // create the page TransformAndWriteResult(_xsltTypeDoc, arguments, filename); }
/// <summary> /// Builds the documentation. /// </summary> public override void Build(NDoc.Core.Project project) { int buildStepProgress = 0; OnDocBuildingStep(buildStepProgress, "Initializing..."); _resourceDirectory = Path.Combine(Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData), "NDoc"), "NAnt"); // get assembly in which documenter is defined Assembly assembly = this.GetType().Module.Assembly; // write xslt files to resource directory EmbeddedResources.WriteEmbeddedResources(assembly, "Documenter.xslt", Path.Combine(_resourceDirectory, "xslt")); // create the html output directories try { Directory.CreateDirectory(OutputDirectory); Directory.CreateDirectory(Path.Combine(OutputDirectory, "elements")); Directory.CreateDirectory(Path.Combine(OutputDirectory, "functions")); Directory.CreateDirectory(Path.Combine(OutputDirectory, "types")); Directory.CreateDirectory(Path.Combine(OutputDirectory, "tasks")); Directory.CreateDirectory(Path.Combine(OutputDirectory, "enums")); Directory.CreateDirectory(Path.Combine(OutputDirectory, "filters")); } catch (Exception ex) { throw new DocumenterException("The output directories could not" + " be created.", ex); } buildStepProgress += 10; OnDocBuildingStep(buildStepProgress, "Merging XML documentation..."); // load the stylesheets that will convert the master xml into html pages MakeTransforms(); // will hold the file name containing the NDoc generated XML string tempFile = null; try { // determine temporary file name tempFile = Path.GetTempFileName(); // create the master XML document MakeXmlFile(project, tempFile); // create a xml document that will be transformed using xslt using (FileStream fs = new FileStream(tempFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { _xmlDocumentation = new XmlDocument(); _xmlDocumentation.Load(fs); } } finally { // ensure temporary file is removed if (tempFile != null) { File.Delete(tempFile); } } // build the file mapping buildStepProgress += 15; OnDocBuildingStep(buildStepProgress, "Building mapping..."); // create arguments for nant index page transform XsltArgumentList indexArguments = CreateXsltArgumentList(); // add extension object for NAnt utilities NAntXsltUtilities indexUtilities = NAntXsltUtilities.CreateInstance( _xmlDocumentation, (NAntDocumenterConfig)Config); // add extension object to Xslt arguments indexArguments.AddExtensionObject("urn:NAntUtil", indexUtilities); buildStepProgress += 15; OnDocBuildingStep(buildStepProgress, "Creating Task Index Page..."); // transform nant task index page transform TransformAndWriteResult(_xsltTaskIndex, indexArguments, "tasks/index.html"); buildStepProgress += 10; OnDocBuildingStep(buildStepProgress, "Creating Type Index Page..."); // transform nant type index page transform TransformAndWriteResult(_xsltTypeIndex, indexArguments, "types/index.html"); buildStepProgress += 10; OnDocBuildingStep(buildStepProgress, "Creating Filter Index Page..."); // transform nant type index page transform TransformAndWriteResult(_xsltFilterIndex, indexArguments, "filters/index.html"); OnDocBuildingStep(buildStepProgress, "Creating Function Index Page..."); // transform nant function index page transform TransformAndWriteResult(_xsltFunctionIndex, indexArguments, "functions/index.html"); buildStepProgress += 10; OnDocBuildingStep(buildStepProgress, "Generating Task Documents..."); // generate a page for each marked task XmlNodeList typeNodes = _xmlDocumentation.SelectNodes("//class[starts-with(substring(@id, 3, string-length(@id) - 2), '" + NamespaceFilter + "')]"); foreach (XmlNode typeNode in typeNodes) { ElementDocType elementDocType = indexUtilities.GetElementDocType(typeNode); DocumentType(typeNode, elementDocType, indexUtilities); } OnDocBuildingStep(buildStepProgress, "Generating Function Documents..."); // generate a page for each function - TODO - change the XPath expression to select more functions XmlNodeList functionNodes = _xmlDocumentation.SelectNodes("//method[attribute/@name = 'NAnt.Core.Attributes.FunctionAttribute' and ancestor::class[starts-with(substring(@id, 3, string-length(@id) - 2), '" + NamespaceFilter + "')]]"); foreach (XmlElement function in functionNodes) { DocumentFunction(function, indexUtilities); } OnDocBuildingStep(100, "Complete"); }