1 package org.unicode.cldr.util; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 import java.util.HashSet; 10 import java.util.List; 11 import java.util.Map; 12 import java.util.Map.Entry; 13 import java.util.Objects; 14 import java.util.Set; 15 import java.util.TreeMap; 16 import java.util.regex.Matcher; 17 import java.util.regex.Pattern; 18 19 import org.unicode.cldr.util.CLDRFile.DraftStatus; 20 import org.unicode.cldr.util.XMLFileReader.AllHandler; 21 import org.xml.sax.Attributes; 22 import org.xml.sax.Locator; 23 import org.xml.sax.SAXException; 24 import org.xml.sax.SAXParseException; 25 26 import com.google.common.cache.CacheBuilder; 27 import com.google.common.cache.CacheLoader; 28 import com.google.common.cache.LoadingCache; 29 import com.google.common.collect.ImmutableSet; 30 import com.ibm.icu.impl.Utility; 31 import com.ibm.icu.text.UnicodeSet; 32 import com.ibm.icu.util.ICUUncheckedIOException; 33 import com.ibm.icu.util.VersionInfo; 34 35 /** 36 * Loading Normalized XMLSource 37 */ 38 public class XMLNormalizingLoader{ 39 40 private static final int CACHE_LIMIT = 700; 41 private static LoadingCache<XMLSourceCacheKey, XMLSource> cache = CacheBuilder.newBuilder() 42 .maximumSize(CACHE_LIMIT) 43 .softValues() // will garbage-collected in LRU manner in response to memory demand 44 .build( 45 new CacheLoader<XMLSourceCacheKey, XMLSource>() { 46 @Override 47 public XMLSource load(XMLSourceCacheKey key) { 48 return makeXMLSource(key); 49 } 50 }); 51 52 private static final boolean LOG_PROGRESS = false; 53 private static final boolean DEBUG = false; 54 enum SupplementalStatus { 55 NEVER_SET, IS_SUMPPLEMENTAL, NOT_SUPPLEMENTAL 56 } 57 58 private static class XMLSourceCacheKey { 59 private final String localeId; 60 private final Set<File> dirs; 61 private final DraftStatus minimalDraftStatus; 62 private final int hashCode; XMLSourceCacheKey(String localeId, List<File> dirs, DraftStatus minimalDraftStatus)63 public XMLSourceCacheKey(String localeId, List<File> dirs, DraftStatus minimalDraftStatus) { 64 this.localeId = localeId; 65 // Parameter check: the directory/file supplied must be non-null and readable. 66 if (dirs == null || dirs.isEmpty()) { 67 throw new ICUUncheckedIOException("Attempt to create a XMLSourceCacheKey with a null directory, please supply a non-null one."); 68 } 69 ImmutableSet.Builder<File> _dirs = ImmutableSet.builder(); 70 for (File dir : dirs) { 71 if (!dir.canRead()) { 72 throw new ICUUncheckedIOException("The directory specified, " + dir.getPath() + ", cannot be read"); 73 } 74 _dirs.add(dir); 75 } 76 this.dirs = _dirs.build(); 77 this.minimalDraftStatus = minimalDraftStatus; 78 this.hashCode = Objects.hash(this.localeId, this.dirs, this.minimalDraftStatus); 79 } 80 81 @Override hashCode()82 public int hashCode() { 83 return hashCode; 84 } 85 86 @Override equals(Object obj)87 public boolean equals(Object obj) { 88 if (this == obj) { 89 return true; 90 } 91 if (obj == null) { 92 return false; 93 } 94 if (getClass() != obj.getClass()) { 95 return false; 96 } 97 XMLSourceCacheKey other = (XMLSourceCacheKey) obj; 98 if(hashCode != other.hashCode) { 99 return false; 100 } 101 if (!Objects.equals(dirs, other.dirs)) { 102 return false; 103 } 104 if (minimalDraftStatus != other.minimalDraftStatus) { 105 return false; 106 } 107 if (!Objects.equals(localeId, other.localeId)) { 108 return false; 109 } 110 return true; 111 } 112 } 113 getFrozenInstance(String localeId, List<File> dirs, DraftStatus minimalDraftStatus)114 public static XMLSource getFrozenInstance(String localeId, List<File> dirs, DraftStatus minimalDraftStatus) { 115 XMLSourceCacheKey key = new XMLSourceCacheKey(localeId, dirs, minimalDraftStatus); 116 return cache.getUnchecked(key); 117 } 118 makeXMLSource(XMLSourceCacheKey key)119 private static XMLSource makeXMLSource(XMLSourceCacheKey key) { 120 XMLSource source = null; 121 if (key.dirs.size() == 1) { 122 File file = new File(key.dirs.iterator().next(), key.localeId + ".xml"); 123 source = loadXMLFile(file, key.localeId, key.minimalDraftStatus); 124 source.freeze(); 125 return source; 126 } 127 128 // if contains more than one file, make XMLSource from each file and then combine them to a combined XMLSource, 129 // so that can cache single file XMLSource as well as combined XMLSource 130 List<XMLSource> list = new ArrayList<>(); 131 List<File> dirList = new ArrayList<>(); 132 for (File dir: key.dirs) { 133 dirList.clear(); 134 dirList.add(dir); 135 XMLSourceCacheKey singleKey = new XMLSourceCacheKey(key.localeId, dirList, key.minimalDraftStatus); 136 XMLSource singleSource = cache.getUnchecked(singleKey); 137 list.add(singleSource); 138 } 139 140 source = list.get(0).cloneAsThawed(); 141 for (int i = 1; i < list.size(); i++) { 142 XMLSource other = list.get(i); 143 source.putAll(other, 0); // 0 --> merge_keep_mine 144 source.getXpathComments().joinAll(other.getXpathComments()); 145 } 146 source.freeze(); 147 return source; 148 } 149 loadXMLFile(File f, String localeId, DraftStatus minimalDraftStatus)150 public static XMLSource loadXMLFile(File f, String localeId, DraftStatus minimalDraftStatus) { 151 // use try-with-resources statement 152 try ( 153 InputStream fis = new FileInputStream(f); 154 ) { 155 String fullFileName = PathUtilities.getNormalizedPathString(f); 156 XMLSource source = new SimpleXMLSource(localeId); 157 XMLNormalizingHandler XML_HANDLER = new XMLNormalizingHandler(source, minimalDraftStatus); 158 XMLFileReader.read(fullFileName, fis, -1, true, XML_HANDLER); 159 if (XML_HANDLER.supplementalStatus == SupplementalStatus.NEVER_SET) { 160 throw new IllegalArgumentException("root of file must be either ldml or supplementalData"); 161 } 162 source.setNonInheriting(XML_HANDLER.supplementalStatus == SupplementalStatus.NOT_SUPPLEMENTAL); 163 if (XML_HANDLER.overrideCount > 0) { 164 throw new IllegalArgumentException("Internal problems: either data file has duplicate path, or" + 165 " CLDRFile.isDistinguishing() or CLDRFile.isOrdered() need updating: " 166 + XML_HANDLER.overrideCount 167 + "; The exact problems are printed on the console above."); 168 } 169 return source; 170 } catch (IOException e) { 171 throw new ICUUncheckedIOException("Cannot read the file " + f, e); 172 } 173 } 174 175 private static class XMLNormalizingHandler implements AllHandler { 176 private DraftStatus minimalDraftStatus; 177 private static final boolean SHOW_START_END = false; 178 private int commentStackIndex; 179 private boolean justPopped = false; 180 private String lastChars = ""; 181 private StringBuilder currentFullXPathSb = new StringBuilder("/"); 182 private String comment = null; 183 private Map<String, String> attributeOrder; 184 private DtdData dtdData; 185 private XMLSource source; 186 private String lastActiveLeafNode; 187 private String lastLeafNode; 188 private SupplementalStatus supplementalStatus = SupplementalStatus.NEVER_SET; 189 private final static int MAX_DEPTH = 30; // just make deep enough to handle any CLDR file. 190 // orderedCounter, orderedString, and level logically form a single class that allows adding elements, but never removed. 191 private int[] orderedCounter = new int[MAX_DEPTH]; 192 private String[] orderedString = new String[MAX_DEPTH]; 193 private int level = 0; 194 private int overrideCount = 0; 195 // Types which changed from 'type' to 'choice', but not in supplemental data. 196 private static final Set<String> CHANGED_TYPES = new HashSet<>(Arrays.asList(new String[] { 197 "abbreviationFallback", 198 "default", "mapping", "measurementSystem", "preferenceOrdering" })); 199 private static final Pattern DRAFT_PATTERN = PatternCache.get("\\[@draft=\"([^\"]*)\"\\]"); 200 private static final Pattern WHITESPACE_WITH_LF = PatternCache.get("\\s*\\u000a\\s*"); 201 private Matcher draftMatcher = DRAFT_PATTERN.matcher(""); 202 private Matcher whitespaceWithLf = WHITESPACE_WITH_LF.matcher(""); 203 private static final UnicodeSet CONTROLS = new UnicodeSet("[:cc:]").freeze(); 204 private static final UnicodeSet WHITESPACE = new UnicodeSet("[:whitespace:]").freeze(); 205 private Locator documentLocator = null; 206 XMLNormalizingHandler(XMLSource source, DraftStatus minimalDraftStatus)207 XMLNormalizingHandler(XMLSource source, DraftStatus minimalDraftStatus) { 208 this.source = source; 209 this.minimalDraftStatus = minimalDraftStatus; 210 } 211 show(Attributes attributes)212 private String show(Attributes attributes) { 213 if (attributes == null) return "null"; 214 StringBuilder result = new StringBuilder(); 215 for (int i = 0; i < attributes.getLength(); ++i) { 216 String attribute = attributes.getQName(i); 217 String value = attributes.getValue(i); 218 result.append( "[@" + attribute + "=\"" + value + "\"]"); // TODO quote the value?? 219 } 220 return result.toString(); 221 } 222 push(String qName, Attributes attributes)223 private void push(String qName, Attributes attributes) { 224 Log.logln(LOG_PROGRESS, "push\t" + qName + "\t" + show(attributes)); 225 ++level; 226 if (!qName.equals(orderedString[level])) { 227 orderedString[level] = qName; 228 } 229 if (lastChars.length() != 0) { 230 if (WHITESPACE.containsAll(lastChars)) 231 lastChars = ""; 232 else 233 throw new IllegalArgumentException("Must not have mixed content: " + qName + ", " 234 + show(attributes) + ", Content: " + lastChars); 235 } 236 237 currentFullXPathSb.append("/" + qName); 238 if (dtdData.isOrdered(qName)) { 239 currentFullXPathSb.append(orderingAttribute()); 240 } 241 if (attributes.getLength() > 0) { 242 attributeOrder.clear(); 243 for (int i = 0; i < attributes.getLength(); ++i) { 244 String attribute = attributes.getQName(i); 245 String value = attributes.getValue(i); 246 247 if (attribute.equals("cldrVersion") 248 && (qName.equals("version"))) { 249 ((SimpleXMLSource) source).setDtdVersionInfo(VersionInfo.getInstance(value)); 250 } else { 251 putAndFixDeprecatedAttribute(qName, attribute, value); 252 } 253 } 254 for (Entry<String, String> entry : attributeOrder.entrySet()) { 255 String attribute = entry.getKey(); 256 String value = entry.getValue(); 257 String both = "[@" + attribute + "=\"" + value + "\"]"; // TODO quote the value?? 258 currentFullXPathSb.append(both); 259 } 260 } 261 if (comment != null) { 262 String currentFullXPath = currentFullXPathSb.toString(); 263 if (currentFullXPath.equals("//ldml") || currentFullXPath.equals("//supplementalData")) { 264 source.setInitialComment(comment); 265 } else { 266 source.addComment(currentFullXPath, comment, XPathParts.Comments.CommentType.PREBLOCK); 267 } 268 comment = null; 269 } 270 justPopped = false; 271 lastActiveLeafNode = null; 272 Log.logln(LOG_PROGRESS, "currentFullXPath\t" + currentFullXPathSb.toString()); 273 } 274 275 orderingAttribute()276 private String orderingAttribute() { 277 return "[@_q=\"" + (orderedCounter[level]++) + "\"]"; 278 } 279 putAndFixDeprecatedAttribute(String element, String attribute, String value)280 private void putAndFixDeprecatedAttribute(String element, String attribute, String value) { 281 if (attribute.equals("draft")) { 282 if (value.equals("true")) { 283 value = "approved"; 284 } 285 else if (value.equals("false")) { 286 value = "unconfirmed"; 287 } 288 } else if (attribute.equals("type")) { 289 if (CHANGED_TYPES.contains(element) && supplementalStatus!= SupplementalStatus.NOT_SUPPLEMENTAL) { // measurementSystem for example did not 290 // change from 'type' to 'choice'. 291 attribute = "choice"; 292 } 293 } 294 295 attributeOrder.put(attribute, value); 296 } 297 298 /** 299 * Adds a parsed XPath to the CLDRFile. 300 * 301 * @param fullXPath 302 * @param value 303 */ addPath(String fullXPath, String value)304 private void addPath(String fullXPath, String value) { 305 String former = source.getValueAtPath(fullXPath); 306 if (former != null) { 307 String formerPath = source.getFullXPath(fullXPath); 308 if (!former.equals(value) || !fullXPath.equals(formerPath)) { 309 if (!fullXPath.startsWith("//ldml/identity/version") && !fullXPath.startsWith("//ldml/identity/generation")) { 310 warnOnOverride(former, formerPath); 311 } 312 } 313 } 314 value = trimWhitespaceSpecial(value); 315 source.add(fullXPath, value) 316 .addSourceLocation(fullXPath, new XMLSource.SourceLocation(documentLocator)); 317 } 318 pop(String qName)319 private void pop(String qName) { 320 Log.logln(LOG_PROGRESS, "pop\t" + qName); 321 --level; 322 String currentFullXPath = currentFullXPathSb.toString(); 323 if (!lastChars.isEmpty() || justPopped == false) { 324 boolean acceptItem = minimalDraftStatus == DraftStatus.unconfirmed; 325 if (!acceptItem) { 326 if (draftMatcher.reset(currentFullXPath).find()) { 327 DraftStatus foundStatus = DraftStatus.valueOf(draftMatcher.group(1)); 328 if (minimalDraftStatus.compareTo(foundStatus) <= 0) { 329 // what we found is greater than or equal to our status 330 acceptItem = true; 331 } 332 } else { 333 acceptItem = true; // if not found, then the draft status is approved, so it is always ok 334 } 335 } 336 if (acceptItem) { 337 // Change any deprecated orientation attributes into values 338 // for backwards compatibility. 339 boolean skipAdd = false; 340 if (currentFullXPath.startsWith("//ldml/layout/orientation")) { 341 XPathParts parts = XPathParts.getFrozenInstance(currentFullXPath); 342 String value = parts.getAttributeValue(-1, "characters"); 343 if (value != null) { 344 addPath("//ldml/layout/orientation/characterOrder", value); 345 skipAdd = true; 346 } 347 value = parts.getAttributeValue(-1, "lines"); 348 if (value != null) { 349 addPath("//ldml/layout/orientation/lineOrder", value); 350 skipAdd = true; 351 } 352 } 353 if (!skipAdd) { 354 addPath(currentFullXPath, lastChars); 355 } 356 lastLeafNode = lastActiveLeafNode = currentFullXPath; 357 } 358 lastChars = ""; 359 } else { 360 Log.logln(LOG_PROGRESS && lastActiveLeafNode != null, "pop: zeroing last leafNode: " 361 + lastActiveLeafNode); 362 lastActiveLeafNode = null; 363 if (comment != null) { 364 source.addComment(lastLeafNode, comment, XPathParts.Comments.CommentType.POSTBLOCK); 365 comment = null; 366 } 367 } 368 currentFullXPathSb.setLength(0); 369 currentFullXPathSb.append(stripAfter(currentFullXPath, qName)); 370 justPopped = true; 371 } 372 373 /** 374 * Trim leading whitespace if there is a linefeed among them, then the same with trailing. 375 * 376 * @param source 377 * @return 378 */ trimWhitespaceSpecial(String source)379 private String trimWhitespaceSpecial(String source) { 380 if (DEBUG && CONTROLS.containsSome(source)) { 381 System.out.println("*** " + source); 382 } 383 if (!source.contains("\n")) { 384 return source; 385 } 386 source = whitespaceWithLf.reset(source).replaceAll("\n"); 387 return source; 388 } 389 warnOnOverride(String former, String formerPath)390 private void warnOnOverride(String former, String formerPath) { 391 String distinguishing = CLDRFile.getDistinguishingXPath(formerPath, null); 392 System.out.println("\tERROR in " + source.getLocaleID() 393 + ";\toverriding old value <" + former + "> at path " + distinguishing + 394 "\twith\t<" + lastChars + ">" + 395 CldrUtility.LINE_SEPARATOR + "\told fullpath: " + formerPath + 396 CldrUtility.LINE_SEPARATOR + "\tnew fullpath: " + currentFullXPathSb.toString()); 397 System.err.println(new XMLSource.SourceLocation(documentLocator) + 398 "Location of error"); 399 overrideCount += 1; 400 } 401 stripAfter(String input, String qName)402 private static String stripAfter(String input, String qName) { 403 int pos = findLastSlash(input); 404 if (qName != null) { 405 // assert input.substring(pos+1).startsWith(qName); 406 if (!input.substring(pos + 1).startsWith(qName)) { 407 throw new IllegalArgumentException("Internal Error: should never get here."); 408 } 409 } 410 return input.substring(0, pos); 411 } 412 findLastSlash(String input)413 private static int findLastSlash(String input) { 414 int braceStack = 0; 415 char inQuote = 0; 416 for (int i = input.length() - 1; i >= 0; --i) { 417 char ch = input.charAt(i); 418 switch (ch) { 419 case '\'': // treat single and double quotes in same way 420 case '"': 421 if (inQuote == 0) { 422 inQuote = ch; 423 } else if (inQuote == ch) { 424 inQuote = 0; // come out of quote 425 } 426 break; 427 case '/': 428 if (inQuote == 0 && braceStack == 0) { 429 return i; 430 } 431 break; 432 case '[': 433 if (inQuote == 0) { 434 --braceStack; 435 } 436 break; 437 case ']': 438 if (inQuote == 0) { 439 ++braceStack; 440 } 441 break; 442 } 443 } 444 return -1; 445 } 446 447 // SAX items we need to catch 448 449 @Override startElement( String uri, String localName, String qName, Attributes attributes)450 public void startElement( 451 String uri, 452 String localName, 453 String qName, 454 Attributes attributes) 455 throws SAXException { 456 Log.logln(LOG_PROGRESS || SHOW_START_END, "startElement uri\t" + uri 457 + "\tlocalName " + localName 458 + "\tqName " + qName 459 + "\tattributes " + show(attributes)); 460 try { 461 if (supplementalStatus == SupplementalStatus.NEVER_SET) { // set by first element 462 attributeOrder = new TreeMap<>( 463 // HACK for ldmlIcu 464 dtdData.dtdType == DtdType.ldml 465 ? CLDRFile.getAttributeOrdering() 466 : dtdData.getAttributeComparator()); 467 supplementalStatus = source.getXMLNormalizingDtdType() == DtdType.ldml ? 468 SupplementalStatus.IS_SUMPPLEMENTAL : SupplementalStatus.NOT_SUPPLEMENTAL; 469 } 470 push(qName, attributes); 471 } catch (RuntimeException e) { 472 e.printStackTrace(); 473 throw e; 474 } 475 } 476 477 @Override endElement(String uri, String localName, String qName)478 public void endElement(String uri, String localName, String qName) 479 throws SAXException { 480 Log.logln(LOG_PROGRESS || SHOW_START_END, "endElement uri\t" + uri + "\tlocalName " + localName 481 + "\tqName " + qName); 482 try { 483 pop(qName); 484 } catch (RuntimeException e) { 485 throw e; 486 } 487 } 488 489 @Override characters(char[] ch, int start, int length)490 public void characters(char[] ch, int start, int length) 491 throws SAXException { 492 try { 493 String value = new String(ch, start, length); 494 Log.logln(LOG_PROGRESS, "characters:\t" + value); 495 // we will strip leading and trailing line separators in another place. 496 // if (value.indexOf(XML_LINESEPARATOR) >= 0) { 497 // value = value.replace(XML_LINESEPARATOR, '\u0020'); 498 // } 499 lastChars += value; 500 justPopped = false; 501 } catch (RuntimeException e) { 502 e.printStackTrace(); 503 throw e; 504 } 505 } 506 507 @Override startDTD(String name, String publicId, String systemId)508 public void startDTD(String name, String publicId, String systemId) throws SAXException { 509 Log.logln(LOG_PROGRESS, "startDTD name: " + name 510 + ", publicId: " + publicId 511 + ", systemId: " + systemId); 512 commentStackIndex++; 513 source.setXMLNormalizingDtdType(DtdType.valueOf(name)); 514 dtdData = DtdData.getInstance(source.getXMLNormalizingDtdType()); 515 } 516 517 @Override endDTD()518 public void endDTD() throws SAXException { 519 Log.logln(LOG_PROGRESS, "endDTD"); 520 commentStackIndex--; 521 } 522 523 @Override comment(char[] ch, int start, int length)524 public void comment(char[] ch, int start, int length) throws SAXException { 525 final String string = new String(ch, start, length); 526 Log.logln(LOG_PROGRESS, commentStackIndex + " comment " + string); 527 try { 528 if (commentStackIndex != 0) return; 529 String comment0 = trimWhitespaceSpecial(string).trim(); 530 if (lastActiveLeafNode != null) { 531 source.addComment(lastActiveLeafNode, comment0, XPathParts.Comments.CommentType.LINE); 532 } else { 533 comment = (comment == null ? comment0 : comment + XPathParts.NEWLINE + comment0); 534 } 535 } catch (RuntimeException e) { 536 e.printStackTrace(); 537 throw e; 538 } 539 } 540 541 @Override ignorableWhitespace(char[] ch, int start, int length)542 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { 543 if (LOG_PROGRESS) 544 Log.logln(LOG_PROGRESS, 545 "ignorableWhitespace length: " + length + ": " + Utility.hex(new String(ch, start, length))); 546 for (int i = start; i < start + length; ++i) { 547 if (ch[i] == '\n') { 548 Log.logln(LOG_PROGRESS && lastActiveLeafNode != null, "\\n: zeroing last leafNode: " 549 + lastActiveLeafNode); 550 lastActiveLeafNode = null; 551 break; 552 } 553 } 554 } 555 556 @Override startDocument()557 public void startDocument() throws SAXException { 558 Log.logln(LOG_PROGRESS, "startDocument"); 559 commentStackIndex = 0; // initialize 560 } 561 562 @Override endDocument()563 public void endDocument() throws SAXException { 564 Log.logln(LOG_PROGRESS, "endDocument"); 565 try { 566 if (comment != null) { 567 source.addComment(null, comment, XPathParts.Comments.CommentType.LINE); 568 } 569 } catch (RuntimeException e) { 570 e.printStackTrace(); 571 throw e; 572 } 573 } 574 575 // ==== The following are just for debugging ===== 576 577 @Override elementDecl(String name, String model)578 public void elementDecl(String name, String model) throws SAXException { 579 Log.logln(LOG_PROGRESS, "Attribute\t" + name + "\t" + model); 580 } 581 582 @Override attributeDecl(String eName, String aName, String type, String mode, String value)583 public void attributeDecl(String eName, String aName, String type, String mode, String value) 584 throws SAXException { 585 Log.logln(LOG_PROGRESS, "Attribute\t" + eName + "\t" + aName + "\t" + type + "\t" + mode + "\t" + value); 586 } 587 588 @Override internalEntityDecl(String name, String value)589 public void internalEntityDecl(String name, String value) throws SAXException { 590 Log.logln(LOG_PROGRESS, "Internal Entity\t" + name + "\t" + value); 591 } 592 593 @Override externalEntityDecl(String name, String publicId, String systemId)594 public void externalEntityDecl(String name, String publicId, String systemId) throws SAXException { 595 Log.logln(LOG_PROGRESS, "Internal Entity\t" + name + "\t" + publicId + "\t" + systemId); 596 } 597 598 @Override processingInstruction(String target, String data)599 public void processingInstruction(String target, String data) 600 throws SAXException { 601 Log.logln(LOG_PROGRESS, "processingInstruction: " + target + ", " + data); 602 } 603 604 @Override skippedEntity(String name)605 public void skippedEntity(String name) 606 throws SAXException { 607 Log.logln(LOG_PROGRESS, "skippedEntity: " + name); 608 } 609 610 @Override setDocumentLocator(Locator locator)611 public void setDocumentLocator(Locator locator) { 612 Log.logln(LOG_PROGRESS, "setDocumentLocator Locator " + locator); 613 documentLocator = locator; 614 } 615 616 @Override startPrefixMapping(String prefix, String uri)617 public void startPrefixMapping(String prefix, String uri) throws SAXException { 618 Log.logln(LOG_PROGRESS, "startPrefixMapping prefix: " + prefix + 619 ", uri: " + uri); 620 } 621 622 @Override endPrefixMapping(String prefix)623 public void endPrefixMapping(String prefix) throws SAXException { 624 Log.logln(LOG_PROGRESS, "endPrefixMapping prefix: " + prefix); 625 } 626 627 @Override startEntity(String name)628 public void startEntity(String name) throws SAXException { 629 Log.logln(LOG_PROGRESS, "startEntity name: " + name); 630 } 631 632 @Override endEntity(String name)633 public void endEntity(String name) throws SAXException { 634 Log.logln(LOG_PROGRESS, "endEntity name: " + name); 635 } 636 637 @Override startCDATA()638 public void startCDATA() throws SAXException { 639 Log.logln(LOG_PROGRESS, "startCDATA"); 640 } 641 642 @Override endCDATA()643 public void endCDATA() throws SAXException { 644 Log.logln(LOG_PROGRESS, "endCDATA"); 645 } 646 647 /* 648 * (non-Javadoc) 649 * 650 * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) 651 */ 652 @Override error(SAXParseException exception)653 public void error(SAXParseException exception) throws SAXException { 654 Log.logln(LOG_PROGRESS || true, "error: " + XMLFileReader.showSAX(exception)); 655 throw exception; 656 } 657 658 /* 659 * (non-Javadoc) 660 * 661 * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) 662 */ 663 @Override fatalError(SAXParseException exception)664 public void fatalError(SAXParseException exception) throws SAXException { 665 Log.logln(LOG_PROGRESS, "fatalError: " + XMLFileReader.showSAX(exception)); 666 throw exception; 667 } 668 669 /* 670 * (non-Javadoc) 671 * 672 * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) 673 */ 674 @Override warning(SAXParseException exception)675 public void warning(SAXParseException exception) throws SAXException { 676 Log.logln(LOG_PROGRESS, "warning: " + XMLFileReader.showSAX(exception)); 677 throw exception; 678 } 679 } 680 } 681