001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.graph.xml;
023
024 import java.io.InputStream;
025 import java.util.ArrayList;
026 import java.util.HashMap;
027 import java.util.LinkedList;
028 import java.util.List;
029 import java.util.Map;
030 import org.jboss.dna.common.monitor.ProgressMonitor;
031 import org.jboss.dna.common.util.StringUtil;
032 import org.jboss.dna.graph.GraphI18n;
033 import org.jboss.dna.graph.properties.Name;
034 import org.jboss.dna.graph.properties.NameFactory;
035 import org.jboss.dna.graph.properties.NamespaceRegistry;
036 import org.jboss.dna.graph.properties.Path;
037 import org.jboss.dna.graph.sequencers.SequencerContext;
038 import org.jboss.dna.graph.sequencers.SequencerOutput;
039 import org.jboss.dna.graph.sequencers.StreamSequencer;
040 import org.xml.sax.Attributes;
041 import org.xml.sax.InputSource;
042 import org.xml.sax.SAXException;
043 import org.xml.sax.SAXNotRecognizedException;
044 import org.xml.sax.SAXNotSupportedException;
045 import org.xml.sax.SAXParseException;
046 import org.xml.sax.XMLReader;
047 import org.xml.sax.ext.DefaultHandler2;
048 import org.xml.sax.helpers.XMLReaderFactory;
049
050 /**
051 * @author John Verhaeg
052 */
053 public class XmlSequencer implements StreamSequencer {
054
055 private static final String DEFAULT_PRIMARY_TYPE = "nt:unstructured";
056 private static final String DECL_HANDLER_FEATURE = "http://xml.org/sax/properties/declaration-handler";
057 private static final String ENTITY_RESOLVER_2_FEATURE = "http://xml.org/sax/features/use-entity-resolver2";
058 private static final String LEXICAL_HANDLER_FEATURE = "http://xml.org/sax/properties/lexical-handler";
059 private static final String RESOLVE_DTD_URIS_FEATURE = "http://xml.org/sax/features/resolve-dtd-uris";
060 private static final String LOAD_EXTERNAL_DTDS_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
061
062 /**
063 * {@inheritDoc}
064 *
065 * @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext,
066 * ProgressMonitor)
067 */
068 public void sequence( InputStream stream,
069 SequencerOutput output,
070 SequencerContext context,
071 ProgressMonitor monitor ) {
072 monitor.beginTask(100.0, GraphI18n.sequencingXmlDocument);
073 XMLReader reader;
074 try {
075 reader = XMLReaderFactory.createXMLReader();
076 Handler handler = new Handler(output, context, monitor);
077 reader.setContentHandler(handler);
078 reader.setErrorHandler(handler);
079 // Ensure handler acting as entity resolver 2
080 reader.setProperty(DECL_HANDLER_FEATURE, handler);
081 // Ensure handler acting as lexical handler
082 reader.setProperty(LEXICAL_HANDLER_FEATURE, handler);
083 // Ensure handler acting as entity resolver 2
084 setFeature(reader, ENTITY_RESOLVER_2_FEATURE, true);
085 // Prevent loading of external DTDs
086 setFeature(reader, LOAD_EXTERNAL_DTDS_FEATURE, false);
087 // Prevent the resolving of DTD entities into fully-qualified URIS
088 setFeature(reader, RESOLVE_DTD_URIS_FEATURE, false);
089 // Parse XML document
090 reader.parse(new InputSource(stream));
091 } catch (Exception error) {
092 context.getLogger(getClass()).error(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
093 monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
094 } finally {
095 monitor.done();
096 }
097 }
098
099 /**
100 * Sets the reader's named feature to the supplied value, only if the feature is not already set to that value. This method
101 * does nothing if the feature is not known to the reader.
102 *
103 * @param reader the reader; may not be null
104 * @param featureName the name of the feature; may not be null
105 * @param value the value for the feature
106 */
107 private void setFeature( XMLReader reader,
108 String featureName,
109 boolean value ) {
110 try {
111 if (reader.getFeature(featureName) != value) {
112 reader.setFeature(featureName, value);
113 }
114 } catch (SAXNotRecognizedException meansFeatureNotRecognized) {
115 } catch (SAXNotSupportedException meansFeatureNotSupported) {
116 }
117 }
118
119 private final class Handler extends DefaultHandler2 {
120
121 private final SequencerOutput output;
122 private final SequencerContext context;
123 private final ProgressMonitor monitor;
124
125 private double progress;
126
127 private Path path; // The DNA path of the node representing the current XML element
128
129 // Cached instances of the name factory and commonly referenced names
130 private final NameFactory nameFactory;
131 private Name primaryTypeName;
132 private Name defaultPrimaryType;
133
134 // Recursive map used to track the number of occurrences of names for elements under a particular path
135 private Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>();
136
137 // The stack of recursive maps being processed, with the head entry being the map for the current path
138 private final LinkedList<Map<Name, List<IndexedName>>> nameToIndexedNamesMapStack = new LinkedList<Map<Name, List<IndexedName>>>();
139
140 // The stack of XML namespace in scope, with the head entry being namespace of the closest ancestor element declaring a
141 // namespace.
142 private final LinkedList<String> nsStack = new LinkedList<String>();
143
144 // Builder used to concatenate concurrent lines of CDATA into a single value.
145 private StringBuilder cDataBuilder;
146
147 // Builder used to concatenate concurrent lines of element content and entity evaluations into a single value.
148 private StringBuilder contentBuilder;
149
150 // The entity being processed
151 private String entity;
152
153 Handler( SequencerOutput output,
154 SequencerContext context,
155 ProgressMonitor monitor ) {
156 assert output != null;
157 assert monitor != null;
158 assert context != null;
159 this.output = output;
160 this.context = context;
161 this.monitor = monitor;
162 // Initialize path to a an empty path relative to the SequencerOutput's target path.
163 path = context.getFactories().getPathFactory().createRelativePath();
164 // Cache name factory since it is frequently used
165 nameFactory = context.getFactories().getNameFactory();
166 }
167
168 /**
169 * <p>
170 * {@inheritDoc}
171 * </p>
172 *
173 * @see org.xml.sax.ext.DefaultHandler2#attributeDecl(java.lang.String, java.lang.String, java.lang.String,
174 * java.lang.String, java.lang.String)
175 */
176 @Override
177 public void attributeDecl( String name,
178 String name2,
179 String type,
180 String mode,
181 String value ) throws SAXException {
182 stopIfCancelled();
183 }
184
185 /**
186 * <p>
187 * {@inheritDoc}
188 * </p>
189 *
190 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
191 */
192 @Override
193 public void characters( char[] ch,
194 int start,
195 int length ) throws SAXException {
196 stopIfCancelled();
197 String content = String.valueOf(ch, start, length);
198 // Check if data should be appended to previously parsed CDATA
199 if (cDataBuilder == null) {
200 // If content is for an entity, replace with entity reference
201 if (entity != null) {
202 content = '&' + entity + ';';
203 }
204 // Check if first line of content
205 if (contentBuilder == null) {
206 contentBuilder = new StringBuilder(content);
207 } else {
208 // Append additional lines or entity evaluations to previous content, separated by a space
209 if (entity == null) {
210 contentBuilder.append(' ');
211 }
212 contentBuilder.append(content);
213 // Text within builder will be output when another element or CDATA is encountered
214 }
215 } else {
216 cDataBuilder.append(ch, start, length);
217 // Text within builder will be output at the end of CDATA
218 }
219 updateProgress();
220 }
221
222 /**
223 * <p>
224 * {@inheritDoc}
225 * </p>
226 *
227 * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int)
228 */
229 @Override
230 public void comment( char[] ch,
231 int start,
232 int length ) throws SAXException {
233 stopIfCancelled();
234 // Output separate nodes for each comment since multiple are allowed
235 startElement(DnaXmlLexicon.COMMENT);
236 output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.COMMENT);
237 output.setProperty(path, DnaXmlLexicon.COMMENT_CONTENT, String.valueOf(ch, start, length));
238 endElement();
239 updateProgress();
240 }
241
242 /**
243 * <p>
244 * {@inheritDoc}
245 * </p>
246 *
247 * @see org.xml.sax.ext.DefaultHandler2#elementDecl(java.lang.String, java.lang.String)
248 */
249 @Override
250 public void elementDecl( String name,
251 String model ) throws SAXException {
252 stopIfCancelled();
253 }
254
255 /**
256 * <p>
257 * {@inheritDoc}
258 * </p>
259 *
260 * @see org.xml.sax.ext.DefaultHandler2#endCDATA()
261 */
262 @Override
263 public void endCDATA() throws SAXException {
264 stopIfCancelled();
265 // Output CDATA built in characters() method
266 output.setProperty(path, DnaXmlLexicon.CDATA_CONTENT, cDataBuilder.toString());
267 endElement();
268 // Null-out builder to free memory
269 cDataBuilder = null;
270 updateProgress();
271 }
272
273 private void endContent() {
274 if (contentBuilder != null) {
275 // Normalize content
276 String content = StringUtil.normalize(contentBuilder.toString());
277 // Null-out builder to setup for subsequent content.
278 // Must be done before call to startElement below to prevent infinite loop.
279 contentBuilder = null;
280 // Skip if nothing in content but whitespace
281 if (content.length() > 0) {
282 // Create separate node for each content entry since entries can be interspersed amongst child elements
283 startElement(DnaXmlLexicon.ELEMENT_CONTENT);
284 output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.ELEMENT_CONTENT);
285 output.setProperty(path, DnaXmlLexicon.ELEMENT_CONTENT, content);
286 endElement();
287 }
288 }
289 }
290
291 /**
292 * <p>
293 * {@inheritDoc}
294 * </p>
295 *
296 * @see org.xml.sax.helpers.DefaultHandler#endDocument()
297 */
298 @Override
299 public void endDocument() throws SAXException {
300 stopIfCancelled();
301 }
302
303 /**
304 * <p>
305 * {@inheritDoc}
306 * </p>
307 *
308 * @see org.xml.sax.ext.DefaultHandler2#endDTD()
309 */
310 @Override
311 public void endDTD() throws SAXException {
312 stopIfCancelled();
313 }
314
315 private void endElement() {
316 // Recover parent's path, namespace, and indexedName map, clearing the ended element's map to free memory
317 path = path.getParent();
318 nameToIndexedNamesMap.clear();
319 nameToIndexedNamesMap = nameToIndexedNamesMapStack.removeFirst();
320 nsStack.removeFirst();
321 }
322
323 /**
324 * <p>
325 * {@inheritDoc}
326 * </p>
327 *
328 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
329 */
330 @Override
331 public void endElement( String uri,
332 String localName,
333 String name ) throws SAXException {
334 stopIfCancelled();
335 // Check if content still needs to be output
336 endContent();
337 endElement();
338 updateProgress();
339 }
340
341 /**
342 * <p>
343 * {@inheritDoc}
344 * </p>
345 *
346 * @see org.xml.sax.ext.DefaultHandler2#endEntity(java.lang.String)
347 */
348 @Override
349 public void endEntity( String name ) throws SAXException {
350 stopIfCancelled();
351 entity = null;
352 updateProgress();
353 }
354
355 /**
356 * <p>
357 * {@inheritDoc}
358 * </p>
359 *
360 * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
361 */
362 @Override
363 public void error( SAXParseException error ) {
364 context.getLogger(XmlSequencer.class).error(error, GraphI18n.errorSequencingXmlDocument, error);
365 monitor.getProblems().addError(error, GraphI18n.errorSequencingXmlDocument, error);
366 }
367
368 /**
369 * <p>
370 * {@inheritDoc}
371 * </p>
372 *
373 * @see org.xml.sax.ext.DefaultHandler2#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String)
374 */
375 @Override
376 public void externalEntityDecl( String name,
377 String publicId,
378 String systemId ) throws SAXException {
379 stopIfCancelled();
380 // Add "synthetic" entity container to path to help prevent name collisions with XML elements
381 Name entityName = DnaDtdLexicon.ENTITY;
382 startElement(entityName);
383 output.setProperty(path, getPrimaryTypeName(), entityName);
384 output.setProperty(path, nameFactory.create(DnaDtdLexicon.NAME), name);
385 output.setProperty(path, nameFactory.create(DnaDtdLexicon.PUBLIC_ID), publicId);
386 output.setProperty(path, nameFactory.create(DnaDtdLexicon.SYSTEM_ID), systemId);
387 endElement();
388 updateProgress();
389 }
390
391 /**
392 * <p>
393 * {@inheritDoc}
394 * </p>
395 *
396 * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
397 */
398 @Override
399 public void fatalError( SAXParseException error ) {
400 context.getLogger(XmlSequencer.class).error(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
401 monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
402 }
403
404 private Name getPrimaryTypeName() {
405 if (primaryTypeName == null) {
406 primaryTypeName = nameFactory.create(NameFactory.JCR_PRIMARY_TYPE);
407 }
408 return primaryTypeName;
409 }
410
411 private Name getDefaultPrimaryType() {
412 if (defaultPrimaryType == null) {
413 defaultPrimaryType = nameFactory.create(DEFAULT_PRIMARY_TYPE);
414 }
415 return defaultPrimaryType;
416 }
417
418 /**
419 * <p>
420 * {@inheritDoc}
421 * </p>
422 *
423 * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int)
424 */
425 @Override
426 public void ignorableWhitespace( char[] ch,
427 int start,
428 int length ) throws SAXException {
429 stopIfCancelled();
430 }
431
432 /**
433 * <p>
434 * {@inheritDoc}
435 * </p>
436 *
437 * @see org.xml.sax.ext.DefaultHandler2#internalEntityDecl(java.lang.String, java.lang.String)
438 */
439 @Override
440 public void internalEntityDecl( String name,
441 String value ) throws SAXException {
442 stopIfCancelled();
443 // Add "synthetic" entity container to path to help prevent name collisions with XML elements
444 Name entityName = DnaDtdLexicon.ENTITY;
445 startElement(entityName);
446 output.setProperty(path, getPrimaryTypeName(), entityName);
447 output.setProperty(path, DnaDtdLexicon.NAME, name);
448 output.setProperty(path, DnaDtdLexicon.VALUE, value);
449 endElement();
450 updateProgress();
451 }
452
453 /**
454 * <p>
455 * {@inheritDoc}
456 * </p>
457 *
458 * @see org.xml.sax.helpers.DefaultHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String)
459 */
460 @Override
461 public void notationDecl( String name,
462 String publicId,
463 String systemId ) throws SAXException {
464 stopIfCancelled();
465 }
466
467 /**
468 * <p>
469 * {@inheritDoc}
470 * </p>
471 *
472 * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String, java.lang.String)
473 */
474 @Override
475 public void processingInstruction( String target,
476 String data ) throws SAXException {
477 stopIfCancelled();
478 // Output separate nodes for each instruction since multiple are allowed
479 Name name = DnaXmlLexicon.PROCESSING_INSTRUCTION;
480 startElement(name);
481 output.setProperty(path, getPrimaryTypeName(), name);
482 output.setProperty(path, DnaXmlLexicon.TARGET, target);
483 output.setProperty(path, DnaXmlLexicon.PROCESSING_INSTRUCTION_CONTENT, data);
484 endElement();
485 updateProgress();
486 }
487
488 /**
489 * <p>
490 * {@inheritDoc}
491 * </p>
492 *
493 * @see org.xml.sax.helpers.DefaultHandler#skippedEntity(java.lang.String)
494 */
495 @Override
496 public void skippedEntity( String name ) throws SAXException {
497 stopIfCancelled();
498 }
499
500 /**
501 * <p>
502 * {@inheritDoc}
503 * </p>
504 *
505 * @see org.xml.sax.ext.DefaultHandler2#startCDATA()
506 */
507 @Override
508 public void startCDATA() throws SAXException {
509 stopIfCancelled();
510 // Output separate nodes for each CDATA since multiple are allowed
511 startElement(DnaXmlLexicon.CDATA);
512 // Prepare builder for concatenating consecutive lines of CDATA
513 cDataBuilder = new StringBuilder();
514 updateProgress();
515 }
516
517 /**
518 * <p>
519 * {@inheritDoc}
520 * </p>
521 *
522 * @see org.xml.sax.helpers.DefaultHandler#startDocument()
523 */
524 @Override
525 public void startDocument() throws SAXException {
526 stopIfCancelled();
527 output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.DOCUMENT);
528 updateProgress();
529 }
530
531 /**
532 * <p>
533 * {@inheritDoc}
534 * </p>
535 *
536 * @see org.xml.sax.ext.DefaultHandler2#startDTD(java.lang.String, java.lang.String, java.lang.String)
537 */
538 @Override
539 public void startDTD( String name,
540 String publicId,
541 String systemId ) throws SAXException {
542 stopIfCancelled();
543 output.setProperty(path, DnaDtdLexicon.NAME, name);
544 output.setProperty(path, DnaDtdLexicon.PUBLIC_ID, publicId);
545 output.setProperty(path, DnaDtdLexicon.SYSTEM_ID, systemId);
546 updateProgress();
547 }
548
549 private void startElement( Name name ) {
550 // Check if content still needs to be output
551 endContent();
552 // Add name to list of indexed names for this element to ensure we use the correct index (which is the size of the
553 // list)
554 List<IndexedName> indexedNames = nameToIndexedNamesMap.get(name);
555 if (indexedNames == null) {
556 indexedNames = new ArrayList<IndexedName>();
557 nameToIndexedNamesMap.put(name, indexedNames);
558 }
559 IndexedName indexedName = new IndexedName();
560 indexedNames.add(indexedName);
561 // Add element name and the appropriate index to the path.
562 // Per the JCR spec, the index must be relative to same-name sibling nodes
563 path = context.getFactories().getPathFactory().create(path, name, indexedNames.size());
564 path = path.getNormalizedPath();
565 // Add the indexed name map to the stack and set the current map to the new element's map
566 nameToIndexedNamesMapStack.addFirst(nameToIndexedNamesMap);
567 nameToIndexedNamesMap = indexedName.nameToIndexedNamesMap;
568 // Set the current namespace to whatever is declared by this element, or if not declared, to its nearest ancestor that
569 // does declare a namespace.
570 String ns = name.getNamespaceUri();
571 if (ns.length() == 0) {
572 nsStack.addFirst(nsStack.isEmpty() ? "" : nsStack.getFirst());
573 } else {
574 nsStack.addFirst(ns);
575 }
576 }
577
578 /**
579 * <p>
580 * {@inheritDoc}
581 * </p>
582 *
583 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String,
584 * org.xml.sax.Attributes)
585 */
586 @Override
587 public void startElement( String uri,
588 String localName,
589 String name,
590 Attributes attributes ) throws SAXException {
591 stopIfCancelled();
592 // Look for the "jcr:name" attribute, and use that if it's there
593 Name type = getDefaultPrimaryType();
594 Name nameObj = nameFactory.create(name);
595 for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
596 String ns = attributes.getURI(ndx);
597 String attrLocalName = attributes.getLocalName(ndx);
598 Object value = attributes.getValue(ndx);
599 String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr");
600 if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) {
601 nameObj = nameFactory.create(value);
602 break;
603 }
604 }
605 startElement(nameObj);
606 output.setProperty(path, getPrimaryTypeName(), type);
607 // Output this element's attributes using the attribute's namespace, if supplied, or the current namespace in scope.
608 String inheritedNs = nsStack.getFirst();
609 for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
610 String ns = attributes.getURI(ndx);
611 String attrLocalName = attributes.getLocalName(ndx);
612 Object value = attributes.getValue(ndx);
613 String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr");
614 if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("primaryType")) {
615 value = nameFactory.create(value);
616 }
617 if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) {
618 continue;
619 }
620 output.setProperty(path, nameFactory.create(ns.length() == 0 ? inheritedNs : ns, attrLocalName), value);
621 }
622 updateProgress();
623 }
624
625 /**
626 * <p>
627 * {@inheritDoc}
628 * </p>
629 *
630 * @see org.xml.sax.ext.DefaultHandler2#startEntity(java.lang.String)
631 */
632 @Override
633 public void startEntity( String name ) throws SAXException {
634 stopIfCancelled();
635 entity = name;
636 updateProgress();
637 }
638
639 /**
640 * <p>
641 * {@inheritDoc}
642 * </p>
643 *
644 * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String, java.lang.String)
645 */
646 @Override
647 public void startPrefixMapping( String prefix,
648 String uri ) throws SAXException {
649 stopIfCancelled();
650 // Register any unregistered namespaces
651 NamespaceRegistry registry = context.getNamespaceRegistry();
652 if (!registry.isRegisteredNamespaceUri(uri)) {
653 registry.register(prefix, uri);
654 }
655 updateProgress();
656 }
657
658 private void stopIfCancelled() throws SAXException {
659 if (monitor.isCancelled()) {
660 throw new SAXException(GraphI18n.canceledSequencingXmlDocument.text());
661 }
662 }
663
664 /**
665 * <p>
666 * {@inheritDoc}
667 * </p>
668 *
669 * @see org.xml.sax.helpers.DefaultHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String,
670 * java.lang.String)
671 */
672 @Override
673 public void unparsedEntityDecl( String name,
674 String publicId,
675 String systemId,
676 String notationName ) throws SAXException {
677 stopIfCancelled();
678 }
679
680 private void updateProgress() {
681 if (progress == 100.0) {
682 progress = 1;
683 } else {
684 progress++;
685 }
686 monitor.worked(progress);
687 }
688
689 /**
690 * <p>
691 * {@inheritDoc}
692 * </p>
693 *
694 * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
695 */
696 @Override
697 public void warning( SAXParseException warning ) {
698 context.getLogger(XmlSequencer.class).warn(warning, GraphI18n.warningSequencingXmlDocument);
699 monitor.getProblems().addWarning(warning, GraphI18n.warningSequencingXmlDocument, warning);
700 }
701 }
702
703 private class IndexedName {
704
705 Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>();
706
707 IndexedName() {
708 }
709 }
710 }