public override XmlElement GetXml() { XmlDocumentFragment df = doc.CreateDocumentFragment(); XmlWriter w = df.CreateNavigator().AppendChild(); serializer.WriteKeyIdentifierClause(w, clause); w.Close(); return((XmlElement)df.FirstChild); }
/// <summary> /// Look up the shared content elements, find their corresponding shared content item and replace the /// elements with the content item value. /// </summary> /// <param name="key">The document key</param> /// <param name="document">The document containing the topic</param> /// <param name="start">The XPath navigator to search for content elements</param> /// <remarks>This method will replace content items within other content items recursively</remarks> private void ResolveContent(string key, XmlDocument document, XPathNavigator start) { List <string> parameters = new List <string>(); // For each kind of shared content element... foreach (SharedContentElement element in elements) { // Find all such elements, convert to an array so as not to cause an error when manipulating the // document, and process each element. foreach (XPathNavigator node in start.Select(element.Path).ToArray()) { // Get the item key string item = node.Evaluate(element.Item).ToString(); // Check for a missing item key if (String.IsNullOrEmpty(item)) { this.WriteMessage(key, MessageLevel.Warn, "A shared content element did not specify an item"); } else { // Extract any parameters parameters.Clear(); XPathNodeIterator parameterNodes = node.Select(element.Parameters); foreach (XPathNavigator parameterNode in parameterNodes) { parameters.Add(parameterNode.GetInnerXml()); } // Find the content item and format the parameters into the value string contentValue = null; if (content.TryGetValue(item, out contentValue)) { try { contentValue = String.Format(CultureInfo.InvariantCulture, contentValue, parameters.ToArray()); } catch (FormatException) { this.WriteMessage(key, MessageLevel.Error, "The shared content item '{0}' " + "could not be formatted with {1} parameters.", item, parameters.Count); } } // Check for missing content if (contentValue == null) { this.WriteMessage(key, MessageLevel.Warn, "Missing shared content item. Tag: " + "'{0}'; Id:'{1}'.", node.LocalName, item); } else { // Store the content in a document fragment XmlDocumentFragment fragment = document.CreateDocumentFragment(); fragment.InnerXml = contentValue; // Resolve any shared content in the fragment this.ResolveContent(key, document, fragment.CreateNavigator()); // Look for an attribute name string attribute = node.Evaluate(element.Attribute).ToString(); // Insert the resolved content... if (String.IsNullOrEmpty(attribute)) { // ...as mixed content XmlWriter writer = node.InsertAfter(); fragment.WriteTo(writer); writer.Close(); } else { // ...as an attribute XPathNavigator parent = node.CreateNavigator(); parent.MoveToParent(); parent.CreateAttribute(String.Empty, attribute, String.Empty, fragment.InnerText); } } } // Keep a reference to the parent element XPathNavigator parentElement = node.CreateNavigator(); parentElement.MoveToParent(); // Remove the node node.DeleteSelf(); // If there is no content left in the parent element, make sure it is self-closing if (!parentElement.HasChildren && !parentElement.IsEmptyElement) { // If the node was already the root then we will have a blank node now and // doing an InsertAfter() will throw an exception. if (parentElement.Name.Length > 0) { // Create a new element XmlWriter attributeWriter = parentElement.InsertAfter(); attributeWriter.WriteStartElement(parentElement.Prefix, parentElement.LocalName, parentElement.NamespaceURI); // Copy attributes to it XmlReader attributeReader = parentElement.ReadSubtree(); attributeReader.Read(); attributeWriter.WriteAttributes(attributeReader, false); attributeReader.Close(); // Close it attributeWriter.WriteEndElement(); attributeWriter.Close(); // Delete the old element parentElement.DeleteSelf(); } else { // If we are inside a tag such as title, removing the content will leave it in the // form "<title />" which is not allowed in HTML. Since this usually means there is // a problem with the shared content or the transforms leading up to this, we will // just report the error here. this.WriteMessage(key, MessageLevel.Error, "Error replacing item. Root document " + "element encountered."); } } } } }
private void ResolveContent(XmlDocument document, XPathNavigator start) { if (_pathSelector == null) { return; } // find all such elements XPathNodeIterator nodeIterator = start.Select(_pathSelector); if (nodeIterator == null || nodeIterator.Count == 0) { return; } // convert to an array so as not to cause an error when manipulating the document XPathNavigator[] nodes = ToArray(nodeIterator); // process each element int nodeCount = nodes.Length; for (int i = 0; i < nodeCount; i++) { XPathNavigator node = nodes[i]; // get the key string item = node.Evaluate(_itemSelector).ToString(); // check for missing key if (String.IsNullOrEmpty(item)) { LogMessage(BuildLoggerLevel.Warn, "A shared content element did not specify an item."); } else { // extract parameters List <string> parameters = new List <string>(); XPathNodeIterator parameter_nodes = node.Select(_parametersSelector); foreach (XPathNavigator parameter_node in parameter_nodes) { string parameter = GetInnerXml(parameter_node); parameters.Add(parameter); } // get the content string content = GetContent(item, parameters.ToArray()); // check for missing content if (content == null) { if (_warnIfNotFound) { LogMessage(BuildLoggerLevel.Warn, String.Format( "Missing shared content item. Tag:'{0}'; Id:'{1}'.", node.LocalName, item)); } if (_deleteIfNotFound) { node.DeleteSelf(); } } else { // store the content in a document fragment XmlDocumentFragment fragment = document.CreateDocumentFragment(); fragment.InnerXml = content; // resolve any shared content in the fragment ResolveContent(document, fragment.CreateNavigator()); // look for an attribute name string attribute = node.Evaluate(_attributeSelector).ToString(); // insert the resolved content if (String.IsNullOrEmpty(attribute)) { // as mixed content XmlWriter writer = node.InsertAfter(); fragment.WriteTo(writer); writer.Close(); } else { // as an attribute XPathNavigator parent = node.CreateNavigator(); parent.MoveToParent(); parent.CreateAttribute(String.Empty, attribute, String.Empty, fragment.InnerText); } } } // keep a reference to the parent element XPathNavigator parentElement = node.CreateNavigator(); parentElement.MoveToParent(); // remove the node node.DeleteSelf(); // if there is no content left in the parent element, make sure it is self-closing if (!parentElement.HasChildren && !parentElement.IsEmptyElement) { //If 'node' was already the root then we will have a blank node now and //doing an InsertAfter() will throw an exception. if (parentElement.Name.Length > 0) { // create a new element XmlWriter attributeWriter = parentElement.InsertAfter(); attributeWriter.WriteStartElement(parentElement.Prefix, parentElement.LocalName, parentElement.NamespaceURI); // copy attributes to it XmlReader attributeReader = parentElement.ReadSubtree(); attributeReader.Read(); attributeWriter.WriteAttributes(attributeReader, false); attributeReader.Close(); // close it attributeWriter.WriteEndElement(); attributeWriter.Close(); // delete the old element parentElement.DeleteSelf(); } else { //if we are inside a tag such as title, removing the content will make it in the //form of <title /> which is not allowed in html. //Since this usually means there is a problem with the shared content or the transforms //leading up to this we will just report the error here. LogMessage(BuildLoggerLevel.Error, "Error replacing item."); } } } }