001package org.jsoup.nodes; 002 003import org.jsoup.parser.ParseSettings; 004import org.jsoup.parser.Parser; 005import org.jspecify.annotations.Nullable; 006 007import java.io.IOException; 008 009/** 010 A comment node. 011 012 @author Jonathan Hedley, jonathan@hedley.net */ 013public class Comment extends LeafNode { 014 /** 015 Create a new comment node. 016 @param data The contents of the comment 017 */ 018 public Comment(String data) { 019 super(data); 020 } 021 022 @Override public String nodeName() { 023 return "#comment"; 024 } 025 026 /** 027 Get the contents of the comment. 028 @return comment content 029 */ 030 public String getData() { 031 return coreValue(); 032 } 033 034 public Comment setData(String data) { 035 coreValue(data); 036 return this; 037 } 038 039 @Override 040 void outerHtmlHead(Appendable accum, int depth, Document.OutputSettings out) throws IOException { 041 if (out.prettyPrint() && ((isEffectivelyFirst() && parentNode instanceof Element && ((Element) parentNode).tag().formatAsBlock()) || (out.outline() ))) 042 indent(accum, depth, out); 043 accum 044 .append("<!--") 045 .append(getData()) 046 .append("-->"); 047 } 048 049 @Override 050 void outerHtmlTail(Appendable accum, int depth, Document.OutputSettings out) {} 051 052 @Override 053 public Comment clone() { 054 return (Comment) super.clone(); 055 } 056 057 /** 058 * Check if this comment looks like an XML Declaration. This is the case when the HTML parser sees an XML 059 * declaration or processing instruction. Other than doctypes, those aren't part of HTML, and will be parsed as a 060 * bogus comment. 061 * @return true if it looks like, maybe, it's an XML Declaration. 062 * @see #asXmlDeclaration() 063 */ 064 public boolean isXmlDeclaration() { 065 String data = getData(); 066 return isXmlDeclarationData(data); 067 } 068 069 private static boolean isXmlDeclarationData(String data) { 070 return (data.length() > 1 && (data.startsWith("!") || data.startsWith("?"))); 071 } 072 073 /** 074 * Attempt to cast this comment to an XML Declaration node. 075 * @return an XML declaration if it could be parsed as one, null otherwise. 076 * @see #isXmlDeclaration() 077 */ 078 public @Nullable XmlDeclaration asXmlDeclaration() { 079 String data = getData(); 080 081 XmlDeclaration decl = null; 082 String declContent = data.substring(1, data.length() - 1); 083 // make sure this bogus comment is not immediately followed by another, treat as comment if so 084 if (isXmlDeclarationData(declContent)) 085 return null; 086 087 String fragment = "<" + declContent + ">"; 088 // use the HTML parser not XML, so we don't get into a recursive XML Declaration on contrived data 089 Document doc = Parser.htmlParser().settings(ParseSettings.preserveCase).parseInput(fragment, baseUri()); 090 if (doc.body().childrenSize() > 0) { 091 Element el = doc.body().child(0); 092 decl = new XmlDeclaration(NodeUtils.parser(doc).settings().normalizeTag(el.tagName()), data.startsWith("!")); 093 decl.attributes().addAll(el.attributes()); 094 } 095 return decl; 096 } 097}