001package org.jsoup.nodes; 002 003import org.jsoup.helper.StringUtil; 004import org.jsoup.helper.Validate; 005import org.jsoup.nodes.Document.OutputSettings.Syntax; 006 007import java.io.IOException; 008 009/** 010 * A {@code <!DOCTYPE>} node. 011 */ 012public class DocumentType extends LeafNode { 013 // todo needs a bit of a chunky cleanup. this level of detail isn't needed 014 public static final String PUBLIC_KEY = "PUBLIC"; 015 public static final String SYSTEM_KEY = "SYSTEM"; 016 private static final String NAME = "name"; 017 private static final String PUB_SYS_KEY = "pubSysKey"; // PUBLIC or SYSTEM 018 private static final String PUBLIC_ID = "publicId"; 019 private static final String SYSTEM_ID = "systemId"; 020 // todo: quirk mode from publicId and systemId 021 022 /** 023 * Create a new doctype element. 024 * @param name the doctype's name 025 * @param publicId the doctype's public ID 026 * @param systemId the doctype's system ID 027 */ 028 public DocumentType(String name, String publicId, String systemId) { 029 Validate.notNull(name); 030 Validate.notNull(publicId); 031 Validate.notNull(systemId); 032 attr(NAME, name); 033 attr(PUBLIC_ID, publicId); 034 if (has(PUBLIC_ID)) { 035 attr(PUB_SYS_KEY, PUBLIC_KEY); 036 } 037 attr(SYSTEM_ID, systemId); 038 } 039 040 /** 041 * Create a new doctype element. 042 * @param name the doctype's name 043 * @param publicId the doctype's public ID 044 * @param systemId the doctype's system ID 045 * @param baseUri unused 046 * @deprecated 047 */ 048 public DocumentType(String name, String publicId, String systemId, String baseUri) { 049 attr(NAME, name); 050 attr(PUBLIC_ID, publicId); 051 if (has(PUBLIC_ID)) { 052 attr(PUB_SYS_KEY, PUBLIC_KEY); 053 } 054 attr(SYSTEM_ID, systemId); 055 } 056 057 /** 058 * Create a new doctype element. 059 * @param name the doctype's name 060 * @param publicId the doctype's public ID 061 * @param systemId the doctype's system ID 062 * @param baseUri unused 063 * @deprecated 064 */ 065 public DocumentType(String name, String pubSysKey, String publicId, String systemId, String baseUri) { 066 attr(NAME, name); 067 if (pubSysKey != null) { 068 attr(PUB_SYS_KEY, pubSysKey); 069 } 070 attr(PUBLIC_ID, publicId); 071 attr(SYSTEM_ID, systemId); 072 } 073 public void setPubSysKey(String value) { 074 if (value != null) 075 attr(PUB_SYS_KEY, value); 076 } 077 078 @Override 079 public String nodeName() { 080 return "#doctype"; 081 } 082 083 @Override 084 void outerHtmlHead(Appendable accum, int depth, Document.OutputSettings out) throws IOException { 085 if (out.syntax() == Syntax.html && !has(PUBLIC_ID) && !has(SYSTEM_ID)) { 086 // looks like a html5 doctype, go lowercase for aesthetics 087 accum.append("<!doctype"); 088 } else { 089 accum.append("<!DOCTYPE"); 090 } 091 if (has(NAME)) 092 accum.append(" ").append(attr(NAME)); 093 if (has(PUB_SYS_KEY)) 094 accum.append(" ").append(attr(PUB_SYS_KEY)); 095 if (has(PUBLIC_ID)) 096 accum.append(" \"").append(attr(PUBLIC_ID)).append('"'); 097 if (has(SYSTEM_ID)) 098 accum.append(" \"").append(attr(SYSTEM_ID)).append('"'); 099 accum.append('>'); 100 } 101 102 @Override 103 void outerHtmlTail(Appendable accum, int depth, Document.OutputSettings out) { 104 } 105 106 private boolean has(final String attribute) { 107 return !StringUtil.isBlank(attr(attribute)); 108 } 109}