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 value = data; 020 } 021 022 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 String toString() { 054 return outerHtml(); 055 } 056 057 @Override 058 public Comment clone() { 059 return (Comment) super.clone(); 060 } 061 062 /** 063 * Check if this comment looks like an XML Declaration. 064 * @return true if it looks like, maybe, it's an XML Declaration. 065 */ 066 public boolean isXmlDeclaration() { 067 String data = getData(); 068 return isXmlDeclarationData(data); 069 } 070 071 private static boolean isXmlDeclarationData(String data) { 072 return (data.length() > 1 && (data.startsWith("!") || data.startsWith("?"))); 073 } 074 075 /** 076 * Attempt to cast this comment to an XML Declaration node. 077 * @return an XML declaration if it could be parsed as one, null otherwise. 078 */ 079 public @Nullable XmlDeclaration asXmlDeclaration() { 080 String data = getData(); 081 082 XmlDeclaration decl = null; 083 String declContent = data.substring(1, data.length() - 1); 084 // make sure this bogus comment is not immediately followed by another, treat as comment if so 085 if (isXmlDeclarationData(declContent)) 086 return null; 087 088 String fragment = "<" + declContent + ">"; 089 // use the HTML parser not XML, so we don't get into a recursive XML Declaration on contrived data 090 Document doc = Parser.htmlParser().settings(ParseSettings.preserveCase).parseInput(fragment, baseUri()); 091 if (doc.body().childrenSize() > 0) { 092 Element el = doc.body().child(0); 093 decl = new XmlDeclaration(NodeUtils.parser(doc).settings().normalizeTag(el.tagName()), data.startsWith("!")); 094 decl.attributes().addAll(el.attributes()); 095 } 096 return decl; 097 } 098}