1 package net.sf.saxon.event; 2 import net.sf.saxon.trans.XPathException; 3 import net.sf.saxon.style.StandardNames; 4 5 import javax.xml.transform.OutputKeys ; 6 import java.util.Properties ; 7 8 15 16 17 public class XMLIndenter extends ProxyReceiver { 18 19 private int level = 0; 20 private int indentSpaces = 3; 21 private String indentChars = "\n "; 22 private boolean sameline = false; 23 private boolean afterStartTag = false; 24 private boolean afterEndTag = true; 25 private boolean allWhite = true; 26 private int line = 0; private int column = 0; private int suppressedAtLevel = -1; 29 private int xmlspace; 30 31 34 35 public void setOutputProperties(Properties props) { 36 String s = props.getProperty(SaxonOutputKeys.INDENT_SPACES); 37 if (s==null) { 38 indentSpaces = 3; 39 } else { 40 try { 41 indentSpaces = Integer.parseInt(s.trim()); 42 } catch (NumberFormatException err) { 43 indentSpaces = 3; 44 } 45 } 46 String omit = props.getProperty(OutputKeys.OMIT_XML_DECLARATION); 47 afterEndTag = omit==null || !omit.trim().equals("yes") || 48 props.getProperty(OutputKeys.DOCTYPE_SYSTEM)!=null ; 49 } 50 51 54 55 public void open() throws XPathException { 56 super.open(); 57 xmlspace = StandardNames.XML_SPACE; 59 } 60 61 64 65 public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { 66 if (afterStartTag || afterEndTag) { 67 indent(); 68 } 69 super.startElement(nameCode, typeCode, locationId, properties); 70 level++; 71 sameline = true; 72 afterStartTag = true; 73 afterEndTag = false; 74 allWhite = true; 75 line = 0; 76 } 77 78 81 82 public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) 83 throws XPathException { 84 if ((nameCode & 0xfffff) == xmlspace && value.equals("preserve") && suppressedAtLevel < 0) { 85 suppressedAtLevel = level; 86 } 87 super.attribute(nameCode, typeCode, value, locationId, properties); 88 } 89 90 93 94 public void endElement() throws XPathException { 95 level--; 96 if (afterEndTag && !sameline) { 97 indent(); 98 } 99 super.endElement(); 100 sameline = false; 101 afterEndTag = true; 102 afterStartTag = false; 103 allWhite = true; 104 line = 0; 105 if (level == (suppressedAtLevel - 1)) { 106 suppressedAtLevel = -1; 107 } 109 } 110 111 114 115 public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { 116 if (afterEndTag) { 117 indent(); 118 } 119 super.processingInstruction(target, data, locationId, properties); 120 afterStartTag = false; 121 afterEndTag = false; 122 } 123 124 127 128 public void characters(CharSequence chars, int locationId, int properties) throws XPathException { 129 for (int i=0; i<chars.length(); i++) { 130 char c = chars.charAt(i); 131 if (c=='\n') { 132 sameline = false; 133 line++; 134 column = 0; 135 } 136 if (!Character.isWhitespace(c)) { 137 allWhite = false; 138 } 139 column++; 140 } 141 super.characters(chars, locationId, properties); 142 if (!allWhite) { 143 afterStartTag = false; 144 afterEndTag = false; 145 } 146 } 147 148 151 152 public void comment(CharSequence chars, int locationId, int properties) throws XPathException { 153 if (afterEndTag) { 154 indent(); 155 } 156 super.comment(chars, locationId, properties); 157 afterStartTag = false; 158 afterEndTag = false; 159 } 160 161 164 165 private void indent() throws XPathException { 166 if (suppressedAtLevel >= 0) { 167 return; 169 } 170 int spaces = level * indentSpaces; 171 if (line>0) { 172 spaces -= column; 173 if (spaces <= 0) { 174 return; } 176 } 177 while (spaces >= indentChars.length()) { 178 indentChars += " "; 179 } 180 int start = (line == 0 ? 0 : 1); 182 super.characters(indentChars.subSequence(start, start+spaces+1), 0, ReceiverOptions.NO_SPECIAL_CHARS); 183 sameline = false; 184 } 185 186 }; 187 188 206 | Popular Tags |