diff --git a/src/main/java/org/jsoup/nodes/Element.java b/src/main/java/org/jsoup/nodes/Element.java index 3d5f8c15fa..ca9760c504 100644 --- a/src/main/java/org/jsoup/nodes/Element.java +++ b/src/main/java/org/jsoup/nodes/Element.java @@ -177,6 +177,20 @@ public Element tagName(String tagName) { return this; } + /** + * Change (rename) the tag of this element. For example, convert a {@code } to a {@code
} with + * {@code el.tagName("div");}. + * + * @param tagName new tag name for this element + * @return this element, for chaining + * @see Elements#tagName(String) + */ + public Element renameTagPreserveProperties(String tagName) { + Validate.notEmptyParam(tagName, "tagName"); + tag = Tag.convertTag(tag, tagName); // maintains the case option of the original parse + return this; + } + /** * Get the Tag for this element. * diff --git a/src/main/java/org/jsoup/parser/Tag.java b/src/main/java/org/jsoup/parser/Tag.java index 97ed500402..2a65b20a6b 100644 --- a/src/main/java/org/jsoup/parser/Tag.java +++ b/src/main/java/org/jsoup/parser/Tag.java @@ -78,6 +78,26 @@ public static Tag valueOf(String tagName, ParseSettings settings) { return tag; } + /** + * Create a new tag with a new name, copying the same characteristics as the old one. + * + * @param tagName Name of tag, e.g. "p". Case insensitive. + * @return The tag, either defined or new generic. + */ + public static Tag convertTag(Tag oldTag, String tagName) { + Validate.notNull(tagName); + Tag tag = new Tag(tagName); + tag.empty = oldTag.empty; + tag.formList = oldTag.formList; + tag.formSubmit = oldTag.formSubmit; + tag.formatAsBlock = oldTag.formatAsBlock; + tag.isBlock = oldTag.isBlock; + tag.preserveWhitespace = oldTag.preserveWhitespace; + tag.selfClosing = oldTag.selfClosing; + + return tag; + } + /** * Get a Tag by name. If not previously defined (unknown), returns a new generic tag, that can do anything. *

diff --git a/src/test/java/org/jsoup/nodes/ElementTest.java b/src/test/java/org/jsoup/nodes/ElementTest.java index 41809af71c..e89b6e9fb0 100644 --- a/src/test/java/org/jsoup/nodes/ElementTest.java +++ b/src/test/java/org/jsoup/nodes/ElementTest.java @@ -1016,6 +1016,39 @@ public void testTagNameSet() { assertEquals("Hello", doc.select("div").first().html()); } + @Test + public void tagNameChangeResetsProperties() { + Document doc = Jsoup.parse(""); + Element img = doc.select("img").first(); + + assertTrue(img.tag().isInline()); + assertTrue(img.tag().isSelfClosing()); + assertFalse(img.isBlock()); + + // When we rename a tag to a new, unregistered name, confirm that its properties are reset, just as if + // we had created one from scratch. + + Tag testTag = Tag.valueOf("jspControl:image", NodeUtils.parser(doc).settings()); + img.tagName("jspControl:image"); + assertEquals(testTag, img.tag()); + } + + @Test + public void testRenameTagPreserveProperties() { + Document doc = Jsoup.parse(""); + Element img = doc.select("img").first(); + assertTrue(img.tag().isInline()); + assertTrue(img.tag().isSelfClosing()); + assertFalse(img.isBlock()); + + // When we rename to an unrecognized tag, but tell the element to keep its tag properties, the previous + // assertions should still hold true. + img.renameTagPreserveProperties("jspControl:image"); + assertTrue(img.tag().isInline()); + assertTrue(img.tag().isSelfClosing()); + assertFalse(img.isBlock()); + } + @Test public void testHtmlContainsOuter() { Document doc = Jsoup.parse("Check

Hello there
");