/// <summary>Start a depth-first traverse of the root and all of its descendants.</summary> /// <param name="root">the root node point to traverse.</param> public virtual void Traverse(iText.StyledXmlParser.Jsoup.Nodes.Node root) { iText.StyledXmlParser.Jsoup.Nodes.Node node = root; int depth = 0; while (node != null) { visitor.Head(node, depth); if (node.ChildNodeSize() > 0) { node = node.ChildNode(0); depth++; } else { while (node.NextSibling() == null && depth > 0) { visitor.Tail(node, depth); node = node.ParentNode(); depth--; } visitor.Tail(node, depth); if (node == root) { break; } node = node.NextSibling(); } } }
/// <summary>Wrap the supplied HTML around this node.</summary> /// <param name="html"> /// HTML to wrap around this element, e.g. /// <c><div class="head"></div></c> /// . Can be arbitrarily deep. /// </param> /// <returns>this node, for chaining.</returns> public virtual iText.StyledXmlParser.Jsoup.Nodes.Node Wrap(String html) { Validate.NotEmpty(html); iText.StyledXmlParser.Jsoup.Nodes.Element context = Parent() is iText.StyledXmlParser.Jsoup.Nodes.Element ? (iText.StyledXmlParser.Jsoup.Nodes.Element)Parent() : null; IList <iText.StyledXmlParser.Jsoup.Nodes.Node> wrapChildren = iText.StyledXmlParser.Jsoup.Parser.Parser.ParseFragment (html, context, BaseUri()); iText.StyledXmlParser.Jsoup.Nodes.Node wrapNode = wrapChildren[0]; if (wrapNode == null || !(wrapNode is iText.StyledXmlParser.Jsoup.Nodes.Element)) { // nothing to wrap with; noop return(null); } iText.StyledXmlParser.Jsoup.Nodes.Element wrap = (iText.StyledXmlParser.Jsoup.Nodes.Element)wrapNode; iText.StyledXmlParser.Jsoup.Nodes.Element deepest = GetDeepChild(wrap); parentNode.ReplaceChild(this, wrap); deepest.AddChildren(this); // remainder (unbalanced wrap, like <div></div><p></p> -- The <p> is remainder if (wrapChildren.Count > 0) { for (int i = 0; i < wrapChildren.Count; i++) { iText.StyledXmlParser.Jsoup.Nodes.Node remainder = wrapChildren[i]; remainder.parentNode.RemoveChild(remainder); wrap.AppendChild(remainder); } } return(this); }
/// <summary>Insert the specified node into the DOM after this node (i.e.</summary> /// <remarks>Insert the specified node into the DOM after this node (i.e. as a following sibling).</remarks> /// <param name="node">to add after this node</param> /// <returns>this node, for chaining</returns> /// <seealso cref="Before(Node)"/> public virtual iText.StyledXmlParser.Jsoup.Nodes.Node After(iText.StyledXmlParser.Jsoup.Nodes.Node node) { Validate.NotNull(node); Validate.NotNull(parentNode); parentNode.AddChildren(siblingIndex + 1, node); return(this); }
/// <summary>Removes this node from the DOM, and moves its children up into the node's parent.</summary> /// <remarks> /// Removes this node from the DOM, and moves its children up into the node's parent. This has the effect of dropping /// the node but keeping its children. /// <para /> /// For example, with the input html: /// <para /> /// <c><div>One <span>Two <b>Three</b></span></div></c> /// <para /> /// Calling /// <c>element.unwrap()</c> /// on the /// <c>span</c> /// element will result in the html: /// <para /> /// <c><div>One Two <b>Three</b></div></c> /// <para /> /// and the /// <c>"Two "</c> /// /// <see cref="TextNode"/> /// being returned. /// </remarks> /// <returns>the first child of this node, after the node has been unwrapped. Null if the node had no children. /// </returns> /// <seealso cref="Remove()"/> /// <seealso cref="Wrap(System.String)"/> public virtual iText.StyledXmlParser.Jsoup.Nodes.Node Unwrap() { Validate.NotNull(parentNode); iText.StyledXmlParser.Jsoup.Nodes.Node firstChild = childNodes.Count > 0 ? childNodes[0] : null; parentNode.AddChildren(siblingIndex, this.ChildNodesAsArray()); this.Remove(); return firstChild; }
// merge multiple <head> or <body> contents into one, delete the remainder, and ensure they are owned by <html> private void NormaliseStructure(String tag, iText.StyledXmlParser.Jsoup.Nodes.Element htmlEl) { Elements elements = this.GetElementsByTag(tag); iText.StyledXmlParser.Jsoup.Nodes.Element master = elements.First(); // will always be available as created above if not existent if (elements.Count > 1) { // dupes, move contents to master IList <iText.StyledXmlParser.Jsoup.Nodes.Node> toMove = new List <iText.StyledXmlParser.Jsoup.Nodes.Node>(); for (int i = 1; i < elements.Count; i++) { iText.StyledXmlParser.Jsoup.Nodes.Node dupe = elements[i]; foreach (iText.StyledXmlParser.Jsoup.Nodes.Node node in dupe.childNodes) { toMove.Add(node); } dupe.Remove(); } foreach (iText.StyledXmlParser.Jsoup.Nodes.Node dupe in toMove) { master.AppendChild(dupe); } } // ensure parented by <html> if (!master.Parent().Equals(htmlEl)) { htmlEl.AppendChild(master); } }
protected internal virtual void RemoveChild(iText.StyledXmlParser.Jsoup.Nodes.Node @out) { Validate.IsTrue(@out.parentNode == this); int index = @out.siblingIndex; childNodes.JRemoveAt(index); ReindexChildren(index); @out.parentNode = null; }
/// <summary> /// Ensures a meta charset (html) or xml declaration (xml) with the current /// encoding used. /// </summary> /// <remarks> /// Ensures a meta charset (html) or xml declaration (xml) with the current /// encoding used. This only applies with /// <see cref="UpdateMetaCharsetElement(bool)">updateMetaCharset</see> /// set to /// <tt>true</tt>, otherwise this method does nothing. /// <ul> /// <li>An exsiting element gets updated with the current charset</li> /// <li>If there's no element yet it will be inserted</li> /// <li>Obsolete elements are removed</li> /// </ul> /// <p><b>Elements used:</b></p> /// <ul> /// <li><b>Html:</b> <i><meta charset="CHARSET"></i></li> /// <li><b>Xml:</b> <i><?xml version="1.0" encoding="CHARSET"></i></li> /// </ul> /// </remarks> private void EnsureMetaCharsetElement() { if (updateMetaCharset) { Syntax syntax = OutputSettings().Syntax(); if (syntax == Syntax.html) { iText.StyledXmlParser.Jsoup.Nodes.Element metaCharset = Select("meta[charset]").First(); if (metaCharset != null) { metaCharset.Attr("charset", Charset().DisplayName()); } else { iText.StyledXmlParser.Jsoup.Nodes.Element head = Head(); if (head != null) { head.AppendElement("meta").Attr("charset", Charset().DisplayName()); } } // Remove obsolete elements Select("meta[name=charset]").Remove(); } else { if (syntax == Syntax.xml) { iText.StyledXmlParser.Jsoup.Nodes.Node node = ChildNodes()[0]; if (node is XmlDeclaration) { XmlDeclaration decl = (XmlDeclaration)node; if (decl.Name().Equals("xml")) { decl.Attr("encoding", Charset().DisplayName()); String version = decl.Attr("version"); if (version != null) { decl.Attr("version", "1.0"); } } else { decl = new XmlDeclaration("xml", baseUri, false); decl.Attr("version", "1.0"); decl.Attr("encoding", Charset().DisplayName()); PrependChild(decl); } } else { XmlDeclaration decl = new XmlDeclaration("xml", baseUri, false); decl.Attr("version", "1.0"); decl.Attr("encoding", Charset().DisplayName()); PrependChild(decl); } } } } }
protected internal virtual void ReparentChild(iText.StyledXmlParser.Jsoup.Nodes.Node child) { if (child.parentNode != null) { child.parentNode.RemoveChild(child); } child.SetParentNode(this); }
protected internal virtual void SetParentNode(iText.StyledXmlParser.Jsoup.Nodes.Node parentNode) { if (this.parentNode != null) { this.parentNode.RemoveChild(this); } this.parentNode = parentNode; }
public virtual void Head(iText.StyledXmlParser.Jsoup.Nodes.Node node, int depth) { try { node.OuterHtmlHead(accum, depth, @out); } catch (System.IO.IOException exception) { throw new SerializationException(exception); } }
public virtual void UnwrapNoChildren() { Document doc = iText.StyledXmlParser.Jsoup.Jsoup.Parse("<div>One <span></span> Two</div>"); iText.StyledXmlParser.Jsoup.Nodes.Element span = doc.Select("span").First(); iText.StyledXmlParser.Jsoup.Nodes.Node node = span.Unwrap(); NUnit.Framework.Assert.AreEqual("<div>One Two</div>", TextUtil.StripNewlines(doc.Body().Html())); NUnit.Framework.Assert.IsTrue(node == null); }
public virtual void Head(iText.StyledXmlParser.Jsoup.Nodes.Node node, int depth) { if (node is iText.StyledXmlParser.Jsoup.Nodes.Element) { iText.StyledXmlParser.Jsoup.Nodes.Element el = (iText.StyledXmlParser.Jsoup.Nodes.Element)node; if (eval.Matches(root, el)) { elements.Add(el); } } }
public virtual void Tail(iText.StyledXmlParser.Jsoup.Nodes.Node node, int depth) { if (!node.NodeName().Equals("#text")) { // saves a void hit. try { node.OuterHtmlTail(accum, depth, @out); } catch (System.IO.IOException exception) { throw new SerializationException(exception); } } }
protected internal virtual void AddChildren(int index, params iText.StyledXmlParser.Jsoup.Nodes.Node[] children ) { Validate.NoNullElements(children); EnsureChildNodes(); for (int i = children.Length - 1; i >= 0; i--) { iText.StyledXmlParser.Jsoup.Nodes.Node @in = children[i]; ReparentChild(@in); childNodes.Add(index, @in); ReindexChildren(index); } }
protected internal virtual void ReplaceChild(iText.StyledXmlParser.Jsoup.Nodes.Node @out, iText.StyledXmlParser.Jsoup.Nodes.Node @in) { Validate.IsTrue(@out.parentNode == this); Validate.NotNull(@in); if (@in.parentNode != null) { @in.parentNode.RemoveChild(@in); } int index = @out.siblingIndex; childNodes[index] = @in; @in.parentNode = this; @in.SetSiblingIndex(index); @out.parentNode = null; }
public virtual void Unwrap() { Document doc = iText.StyledXmlParser.Jsoup.Jsoup.Parse("<div>One <span>Two <b>Three</b></span> Four</div>" ); iText.StyledXmlParser.Jsoup.Nodes.Element span = doc.Select("span").First(); iText.StyledXmlParser.Jsoup.Nodes.Node twoText = span.ChildNode(0); iText.StyledXmlParser.Jsoup.Nodes.Node node = span.Unwrap(); NUnit.Framework.Assert.AreEqual("<div>One Two <b>Three</b> Four</div>", TextUtil.StripNewlines(doc.Body(). Html())); NUnit.Framework.Assert.IsTrue(node is TextNode); NUnit.Framework.Assert.AreEqual("Two ", ((TextNode)node).Text()); NUnit.Framework.Assert.AreEqual(node, twoText); NUnit.Framework.Assert.AreEqual(node.Parent(), doc.Select("div").First()); }
/* * Return a clone of the node using the given parent (which can be null). * Not a deep copy of children. */ protected internal virtual iText.StyledXmlParser.Jsoup.Nodes.Node DoClone(iText.StyledXmlParser.Jsoup.Nodes.Node parent) { iText.StyledXmlParser.Jsoup.Nodes.Node clone; clone = (iText.StyledXmlParser.Jsoup.Nodes.Node)MemberwiseClone(); clone.parentNode = parent; // can be null, to create an orphan split clone.siblingIndex = parent == null ? 0 : siblingIndex; clone.attributes = attributes != null ? (iText.StyledXmlParser.Jsoup.Nodes.Attributes)attributes.Clone() : null; clone.baseUri = baseUri; clone.childNodes = new List<iText.StyledXmlParser.Jsoup.Nodes.Node>(childNodes.Count); foreach (iText.StyledXmlParser.Jsoup.Nodes.Node child in childNodes) { clone.childNodes.Add(child); } return clone; }
/// <summary>Create a stand-alone, deep copy of this node, and all of its children.</summary> /// <remarks> /// Create a stand-alone, deep copy of this node, and all of its children. The cloned node will have no siblings or /// parent node. As a stand-alone object, any changes made to the clone or any of its children will not impact the /// original node. /// <para /> /// The cloned node may be adopted into another Document or node structure using /// <see cref="Element.AppendChild(Node)"/> /// . /// </remarks> /// <returns>stand-alone cloned node</returns> public virtual Object Clone() { iText.StyledXmlParser.Jsoup.Nodes.Node thisClone = DoClone(null); // splits for orphan // Queue up nodes that need their children cloned (BFS). LinkedList<iText.StyledXmlParser.Jsoup.Nodes.Node> nodesToProcess = new LinkedList<iText.StyledXmlParser.Jsoup.Nodes.Node >(); nodesToProcess.Add(thisClone); while (!nodesToProcess.IsEmpty()) { iText.StyledXmlParser.Jsoup.Nodes.Node currParent = nodesToProcess.JRemove(); for (int i = 0; i < currParent.childNodes.Count; i++) { iText.StyledXmlParser.Jsoup.Nodes.Node childClone = currParent.childNodes[i].DoClone(currParent); currParent.childNodes[i] = childClone; nodesToProcess.Add(childClone); } } return thisClone; }
// does not recurse. private void NormaliseTextNodes(iText.StyledXmlParser.Jsoup.Nodes.Element element) { IList <iText.StyledXmlParser.Jsoup.Nodes.Node> toMove = new List <iText.StyledXmlParser.Jsoup.Nodes.Node>(); foreach (iText.StyledXmlParser.Jsoup.Nodes.Node node in element.childNodes) { if (node is TextNode) { TextNode tn = (TextNode)node; if (!tn.IsBlank()) { toMove.Add(tn); } } } for (int i = toMove.Count - 1; i >= 0; i--) { iText.StyledXmlParser.Jsoup.Nodes.Node node = toMove[i]; element.RemoveChild(node); Body().PrependChild(new TextNode(" ", "")); Body().PrependChild(node); } }
public void Tail(iText.StyledXmlParser.Jsoup.Nodes.Node node, int depth) { accum.Append("</" + node.NodeName() + ">"); }
/// <summary>Insert the specified node into the DOM before this node (i.e.</summary> /// <remarks>Insert the specified node into the DOM before this node (i.e. as a preceding sibling).</remarks> /// <param name="node">to add before this node</param> /// <returns>this node, for chaining</returns> /// <seealso cref="After(Node)"/> public virtual iText.StyledXmlParser.Jsoup.Nodes.Node Before(iText.StyledXmlParser.Jsoup.Nodes.Node node) { Validate.NotNull(node); Validate.NotNull(parentNode); parentNode.AddChildren(siblingIndex, node); return this; }
/// <summary>Replace this node in the DOM with the supplied node.</summary> /// <param name="in">the node that will will replace the existing node.</param> public virtual void ReplaceWith(iText.StyledXmlParser.Jsoup.Nodes.Node @in) { Validate.NotNull(@in); Validate.NotNull(parentNode); parentNode.ReplaceChild(this, @in); }
// includes remove() // fast method to get first by tag name, used for html, head, body finders private iText.StyledXmlParser.Jsoup.Nodes.Element FindFirstElementByTagName(String tag, iText.StyledXmlParser.Jsoup.Nodes.Node node) { if (node.NodeName().Equals(tag)) { return((iText.StyledXmlParser.Jsoup.Nodes.Element)node); } else { foreach (iText.StyledXmlParser.Jsoup.Nodes.Node child in node.childNodes) { iText.StyledXmlParser.Jsoup.Nodes.Element found = FindFirstElementByTagName(tag, child); if (found != null) { return(found); } } } return(null); }
public void Tail(iText.StyledXmlParser.Jsoup.Nodes.Node node, int depth) { }
public void Head(iText.StyledXmlParser.Jsoup.Nodes.Node node, int depth) { node.baseUri = baseUri; }
/// <summary> /// Creates a new /// <see cref="JsoupNode"/> /// instance. /// </summary> /// <param name="node">the node</param> public JsoupNode(iText.StyledXmlParser.Jsoup.Nodes.Node node) { this.node = node; }