Changeset 1344
- Timestamp:
- 02/07/09 14:04:36 (8 months ago)
- Files:
-
- trunk/universe/kauri-template/src/main/java/org/kauriproject/template/DefaultTemplateBuilder.java (modified) (10 diffs)
- trunk/universe/kauri-template/src/main/java/org/kauriproject/template/Directive.java (modified) (2 diffs)
- trunk/universe/kauri-template/src/test/java/org/kauriproject/template/TemplateExecutionTest.java (modified) (3 diffs)
- trunk/universe/kauri-template/src/test/java/org/kauriproject/template/TemplateServiceTest.java (modified) (3 diffs)
- trunk/universe/kauri-template/src/test/java/org/kauriproject/template/TemplateTestBase.java (modified) (6 diffs)
- trunk/universe/kauri-template/src/test/resources/org/kauriproject/template/whitespace.xml (added)
- trunk/universe/kauri-template/src/test/resources/org/kauriproject/template/whitespace_result.xml (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/universe/kauri-template/src/main/java/org/kauriproject/template/DefaultTemplateBuilder.java
r1332 r1344 16 16 package org.kauriproject.template; 17 17 18 import java.io.IOException;19 18 import java.io.InputStream; 20 19 import java.util.ArrayList; … … 64 63 // TODO: (bug) namespace declarations on KTL directives might be ignored (issue #37) 65 64 protected NamespaceSupport namespaceSupport; 65 /** 66 * This stack contains an entry for each nested XML element: either true (whitespace should be stripped), 67 * false (whitespace should not be stripped) or null (no change, first non-null value in the stack 68 * tells what to do with whitespace). 69 */ 70 protected List<Boolean> preserveWhitespaceStack; 66 71 67 72 protected DocumentBlock docblock; … … 100 105 this.silent = silent; 101 106 this.saxParser = createSAXParser(); 107 this.preserveWhitespaceStack = new ArrayList<Boolean>(); 102 108 } 103 109 … … 273 279 } 274 280 281 if (silencedLevel > 0) { 282 silencedLevel++; 283 return; 284 } 285 275 286 // We only want to take care of the prefix mapping events, and remove the duplicate 276 287 // info from the xmlns attributes (which may or may not be present, depending on parser settings) 277 288 attributes = removeXmlnsAttrs(attributes); 278 289 290 // Determine preference for whitespace treatment, if any 291 Boolean preserveWhitespace = null; 292 if (localName.equals(Directive.TEXT.getTagName()) && uri.equals(NAMESPACE_KTL)) { 293 preserveWhitespace = Boolean.TRUE; 294 } else if (attributes.getIndex("http://www.w3.org/XML/1998/namespace", "space") != -1) { 295 int index = attributes.getIndex("http://www.w3.org/XML/1998/namespace", "space"); 296 String space = attributes.getValue(index); 297 if (space.equals("preserve")) { 298 preserveWhitespace = Boolean.TRUE; 299 } else if (space.equals("default")) { 300 preserveWhitespace = Boolean.FALSE; 301 } else { 302 log.warn("Invalid value for xml:space attribute: " + space); 303 } 304 // Remove xml:space from the attributes 305 AttributesImpl newAttrs = new AttributesImpl(attributes); 306 newAttrs.removeAttribute(index); 307 attributes = newAttrs; 308 } 309 preserveWhitespaceStack.add(preserveWhitespace); 310 279 311 if (allowedLevel > 0) { 280 312 allowedLevel++; … … 282 314 283 315 int blocksPushed = 1; 284 if (silencedLevel > 0) {285 silencedLevel++;286 return;287 }288 316 289 317 String bundleName = attributes.getValue(NAMESPACE_I18N, "bundle"); … … 434 462 attributes)); 435 463 pushBlock(protectblock); 464 } else if (Directive.TEXT == directive) { 465 // don't push a block 436 466 } else { 437 467 log.warn("Unsupported KTL directive: " + localName); … … 489 519 ClassCastException { 490 520 521 // revert to previous context 522 namespaceSupport.popContext(); 523 491 524 if (silencedLevel > 0) { 492 525 silencedLevel--; 526 } else if (localName.equals(Directive.TEXT.getTagName()) && uri.equals(NAMESPACE_KTL)) { 527 // The text instruction does not have a runtime block 528 sendCharacters(); 493 529 } else { 494 530 sendCharacters(); … … 499 535 popBlock(); 500 536 501 // revert to previous context502 namespaceSupport.popContext();503 504 537 if (allowedLevel > 0) 505 538 allowedLevel--; … … 508 541 } 509 542 543 // Popping the preserve-whitespace-stack should be done after sendCharacters() 544 preserveWhitespaceStack.remove(preserveWhitespaceStack.size() - 1); 510 545 } 511 546 512 547 @Override 513 548 public void characters(char[] ch, int start, int length) throws SAXException { 514 // TODO: improve whitespace handling (issue #38) 515 String string = String.valueOf(ch).substring(start, start + length).trim(); 516 if (string.length() > 0 && silencedLevel == 0) { 517 // text: e.g. HelloWorld 549 if (silencedLevel == 0) { 518 550 // We have to buffer the characters events, because the parser 519 551 // may split up a single textblock in multiple events. … … 525 557 private void sendCharacters() { 526 558 if (charBuffer.length() > 0) { 527 String chars = charBuffer.toString(); 528 TextStep text = new TextStep(elFacade, charLocator, chars.toCharArray(), 0, chars.length()); 529 last.setCompiledNext(text); 530 last = text; 559 boolean ws = isWhitespace(charBuffer); 560 if (!ws || preserveWhitespace()) { 561 String chars = charBuffer.toString(); 562 TextStep text = new TextStep(elFacade, charLocator, chars.toCharArray(), 0, chars.length()); 563 last.setCompiledNext(text); 564 last = text; 565 } 531 566 charBuffer = new StringBuffer(); 532 567 } 568 } 569 570 private boolean isWhitespace(StringBuffer buffer) { 571 // We follow the same rules as for XSLT to decide if a character is whitespace 572 for (int i = 0; i < buffer.length(); i++) { 573 char c = buffer.charAt(i); 574 if (c != 0x000D && c != 0x000A && c != 0x0009 && c != 0x020) 575 return false; 576 } 577 return true; 578 } 579 580 private boolean preserveWhitespace() { 581 int size = preserveWhitespaceStack.size(); 582 for (int i = size - 1; i >= 0; i--) { 583 if (preserveWhitespaceStack.get(i) != null) { 584 return preserveWhitespaceStack.get(i); 585 } 586 } 587 // By default, pure-whitespace text between tags is stripped 588 return false; 533 589 } 534 590 trunk/universe/kauri-template/src/main/java/org/kauriproject/template/Directive.java
r1108 r1344 108 108 */ 109 109 INIT("init"), 110 PROTECT("protect"); 110 PROTECT("protect"), 111 TEXT("text"); 111 112 112 113 private final String tagName; … … 159 160 else if (name.equals(PROTECT.tagName)) 160 161 return PROTECT; 162 else if (name.equals(TEXT.tagName)) 163 return TEXT; 161 164 else 162 165 return null;// throw RuntimeException ? trunk/universe/kauri-template/src/test/java/org/kauriproject/template/TemplateExecutionTest.java
r1005 r1344 131 131 testFlow("/org/kauriproject/template/init_special.xml", true); 132 132 // special should yield the same result as flat 133 String result1 = loadXML("/org/kauriproject/template/init_flat_result.xml" );134 String result2 = loadXML("/org/kauriproject/template/init_special_result.xml" );133 String result1 = loadXML("/org/kauriproject/template/init_flat_result.xml", true); 134 String result2 = loadXML("/org/kauriproject/template/init_special_result.xml", true); 135 135 assertEquals("Both results should be equal to get a useful test.", result1, result2); 136 136 } … … 156 156 } 157 157 158 public void testWhitespace() throws Exception { 159 testFlow("/org/kauriproject/template/whitespace.xml", null, true, false); 160 } 161 158 162 public void testVariableFromSrc() throws Exception { 159 163 Map<String, Object> parameters = new HashMap<String, Object>(); … … 162 166 testFlow("/org/kauriproject/template/variable_from_src.xml", parameters, true); 163 167 } 164 168 165 169 public void testXmlVariables() throws Exception { 166 170 Map<String, Object> variables = new HashMap<String, Object>(); trunk/universe/kauri-template/src/test/java/org/kauriproject/template/TemplateServiceTest.java
r487 r1344 49 49 // check result 50 50 if (check) { 51 checkResult(template, bos );51 checkResult(template, bos, true); 52 52 } 53 53 } … … 60 60 String template = "/org/kauriproject/template/mix.xml"; 61 61 if (TEST_DURATION) { 62 initTresholds(template );62 initTresholds(template, true); 63 63 } 64 64 testService(template, true, flowTreshold); … … 68 68 String template = "/org/kauriproject/template/big.xml"; 69 69 if (TEST_DURATION) { 70 initTresholds(template );70 initTresholds(template, true); 71 71 } 72 72 // test it three times in a row trunk/universe/kauri-template/src/test/java/org/kauriproject/template/TemplateTestBase.java
r1004 r1344 17 17 18 18 import java.io.ByteArrayOutputStream; 19 import java.io.InputStreamReader; 20 import java.io.Reader; 21 import java.io.BufferedReader; 19 22 import java.util.Date; 20 23 import java.util.HashMap; … … 69 72 } 70 73 71 protected void initTresholds(String template ) throws Exception {74 protected void initTresholds(String template, boolean prettyFormat) throws Exception { 72 75 long start = new Date().getTime(); 73 76 // load template 74 loadXML(template );77 loadXML(template, prettyFormat); 75 78 long end = new Date().getTime(); 76 79 // check duration … … 150 153 } 151 154 155 protected void testFlow(String template, Map<String, Object> variables, boolean check) throws Exception { 156 testFlow(template, variables, check, true); 157 } 158 152 159 /** 153 160 * Load, build and execute template and optionally check the result. 154 161 */ 155 protected void testFlow(String template, Map<String, Object> variables, boolean check) throws Exception { 162 protected void testFlow(String template, Map<String, Object> variables, boolean check, boolean prettyFormat) 163 throws Exception { 156 164 // init tresholds for duration 157 165 if (TEST_DURATION) { 158 initTresholds(template); 159 } 166 initTresholds(template, prettyFormat); 167 } 168 160 169 // monitor duration 161 170 long start = new Date().getTime(); 171 162 172 // load and build template 163 173 CompiledTemplate compiledTemplate = buildTemplate(template, buildTreshold); 174 164 175 // execute template 165 176 ByteArrayOutputStream outputResult = new ByteArrayOutputStream(); 166 TemplateResult result = new TemplateResultImpl(new KauriSaxHandler.NamespaceAsAttributes( 167 new TestHandler(outputResult))); 177 TemplateResult result; 178 if (prettyFormat) { 179 result = new TemplateResultImpl(new KauriSaxHandler.NamespaceAsAttributes( 180 new TestHandler(outputResult))); 181 } else { 182 result = new TemplateResultImpl(new KauriSaxHandler(outputResult)); 183 } 168 184 executeTemplate(compiledTemplate, result, variables, executionTreshold); 185 169 186 // flush result 170 187 result.flush(); … … 180 197 // check result 181 198 if (check) { 182 checkResult(template, outputResult );199 checkResult(template, outputResult, prettyFormat); 183 200 } 184 201 } … … 187 204 * Check if the templateresult meets our expectations. 188 205 */ 189 protected void checkResult(String filename, ByteArrayOutputStream bos ) throws Exception {206 protected void checkResult(String filename, ByteArrayOutputStream bos, boolean prettyFormat) throws Exception { 190 207 String expectedFile = filename.replace(".xml", "_result.xml"); 191 String expectedString = loadXML(expectedFile );208 String expectedString = loadXML(expectedFile, prettyFormat); 192 209 String actualString = bos.toString(ENCODING); 193 210 if (!expectedString.equals(actualString)) { … … 202 219 } 203 220 204 protected String loadXML(String filename ) throws Exception {221 protected String loadXML(String filename, boolean prettyFormat) throws Exception { 205 222 Source source = sourceResolver.resolve(filename); 206 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 207 XmlConsumer consumer = new TestHandler(bos); 208 XMLReader reader = parser.getXMLReader(); 209 reader.setContentHandler(consumer); 210 reader.setProperty("http://xml.org/sax/properties/lexical-handler", consumer); 211 reader.parse(new InputSource(source.getInputStream())); 212 String xmlString = bos.toString(ENCODING); 213 214 return xmlString; 223 if (prettyFormat) { 224 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 225 XmlConsumer consumer = new TestHandler(bos); 226 XMLReader reader = parser.getXMLReader(); 227 reader.setContentHandler(consumer); 228 reader.setProperty("http://xml.org/sax/properties/lexical-handler", consumer); 229 reader.parse(new InputSource(source.getInputStream())); 230 String xmlString = bos.toString(ENCODING); 231 232 return xmlString; 233 } else { 234 BufferedReader reader = new BufferedReader(new InputStreamReader(source.getInputStream(), "UTF-8")); 235 StringBuilder content = new StringBuilder(); 236 String line; 237 while ((line = reader.readLine()) != null) { 238 if (content.length() > 0) 239 content.append("\n"); 240 content.append(line); 241 } 242 reader.close(); 243 return content.toString(); 244 } 215 245 } 216 246
