View Javadoc
1   // =================== DO NOT EDIT THIS FILE ====================
2   //  Generated by Modello Velocity from reader-stax.vm
3   //  template, any modifications will be overwritten.
4   // ==============================================================
5   package org.apache.maven.metadata.v4;
6   
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.io.Reader;
10  import java.text.DateFormat;
11  import java.util.ArrayList;
12  import java.util.Collections;
13  import java.util.Date;
14  import java.util.HashMap;
15  import java.util.HashSet;
16  import java.util.LinkedHashMap;
17  import java.util.List;
18  import java.util.Map;
19  import java.util.Set;
20  import org.apache.maven.api.annotations.Generated;
21  import org.apache.maven.api.metadata.Metadata;
22  import org.apache.maven.api.metadata.Versioning;
23  import org.apache.maven.api.metadata.Snapshot;
24  import org.apache.maven.api.metadata.SnapshotVersion;
25  import org.apache.maven.api.metadata.Plugin;
26  import org.apache.maven.internal.xml.XmlNodeStaxBuilder;
27  import org.apache.maven.api.xml.XmlNode;
28  import javax.xml.stream.XMLInputFactory;
29  import javax.xml.stream.XMLStreamException;
30  import javax.xml.stream.XMLStreamReader;
31  import javax.xml.transform.stream.StreamSource;
32  
33  import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
34  import static javax.xml.XMLConstants.XML_NS_URI;
35  
36  @Generated
37  public class MetadataStaxReader {
38  
39      private static final Map<String, String> DEFAULT_ENTITIES;
40      static {
41          Map<String, String> entities = new HashMap<>();
42          entities.put("nbsp", "\u00a0");
43          entities.put("iexcl", "\u00a1");
44          entities.put("cent", "\u00a2");
45          entities.put("pound", "\u00a3");
46          entities.put("curren", "\u00a4");
47          entities.put("yen", "\u00a5");
48          entities.put("brvbar", "\u00a6");
49          entities.put("sect", "\u00a7");
50          entities.put("uml", "\u00a8");
51          entities.put("copy", "\u00a9");
52          entities.put("ordf", "\u00aa");
53          entities.put("laquo", "\u00ab");
54          entities.put("not", "\u00ac");
55          entities.put("shy", "\u00ad");
56          entities.put("reg", "\u00ae");
57          entities.put("macr", "\u00af");
58          entities.put("deg", "\u00b0");
59          entities.put("plusmn", "\u00b1");
60          entities.put("sup2", "\u00b2");
61          entities.put("sup3", "\u00b3");
62          entities.put("acute", "\u00b4");
63          entities.put("micro", "\u00b5");
64          entities.put("para", "\u00b6");
65          entities.put("middot", "\u00b7");
66          entities.put("cedil", "\u00b8");
67          entities.put("sup1", "\u00b9");
68          entities.put("ordm", "\u00ba");
69          entities.put("raquo", "\u00bb");
70          entities.put("frac14", "\u00bc");
71          entities.put("frac12", "\u00bd");
72          entities.put("frac34", "\u00be");
73          entities.put("iquest", "\u00bf");
74          entities.put("Agrave", "\u00c0");
75          entities.put("Aacute", "\u00c1");
76          entities.put("Acirc", "\u00c2");
77          entities.put("Atilde", "\u00c3");
78          entities.put("Auml", "\u00c4");
79          entities.put("Aring", "\u00c5");
80          entities.put("AElig", "\u00c6");
81          entities.put("Ccedil", "\u00c7");
82          entities.put("Egrave", "\u00c8");
83          entities.put("Eacute", "\u00c9");
84          entities.put("Ecirc", "\u00ca");
85          entities.put("Euml", "\u00cb");
86          entities.put("Igrave", "\u00cc");
87          entities.put("Iacute", "\u00cd");
88          entities.put("Icirc", "\u00ce");
89          entities.put("Iuml", "\u00cf");
90          entities.put("ETH", "\u00d0");
91          entities.put("Ntilde", "\u00d1");
92          entities.put("Ograve", "\u00d2");
93          entities.put("Oacute", "\u00d3");
94          entities.put("Ocirc", "\u00d4");
95          entities.put("Otilde", "\u00d5");
96          entities.put("Ouml", "\u00d6");
97          entities.put("times", "\u00d7");
98          entities.put("Oslash", "\u00d8");
99          entities.put("Ugrave", "\u00d9");
100         entities.put("Uacute", "\u00da");
101         entities.put("Ucirc", "\u00db");
102         entities.put("Uuml", "\u00dc");
103         entities.put("Yacute", "\u00dd");
104         entities.put("THORN", "\u00de");
105         entities.put("szlig", "\u00df");
106         entities.put("agrave", "\u00e0");
107         entities.put("aacute", "\u00e1");
108         entities.put("acirc", "\u00e2");
109         entities.put("atilde", "\u00e3");
110         entities.put("auml", "\u00e4");
111         entities.put("aring", "\u00e5");
112         entities.put("aelig", "\u00e6");
113         entities.put("ccedil", "\u00e7");
114         entities.put("egrave", "\u00e8");
115         entities.put("eacute", "\u00e9");
116         entities.put("ecirc", "\u00ea");
117         entities.put("euml", "\u00eb");
118         entities.put("igrave", "\u00ec");
119         entities.put("iacute", "\u00ed");
120         entities.put("icirc", "\u00ee");
121         entities.put("iuml", "\u00ef");
122         entities.put("eth", "\u00f0");
123         entities.put("ntilde", "\u00f1");
124         entities.put("ograve", "\u00f2");
125         entities.put("oacute", "\u00f3");
126         entities.put("ocirc", "\u00f4");
127         entities.put("otilde", "\u00f5");
128         entities.put("ouml", "\u00f6");
129         entities.put("divide", "\u00f7");
130         entities.put("oslash", "\u00f8");
131         entities.put("ugrave", "\u00f9");
132         entities.put("uacute", "\u00fa");
133         entities.put("ucirc", "\u00fb");
134         entities.put("uuml", "\u00fc");
135         entities.put("yacute", "\u00fd");
136         entities.put("thorn", "\u00fe");
137         entities.put("yuml", "\u00ff");
138 
139         // ----------------------------------------------------------------------
140         // Special entities
141         // ----------------------------------------------------------------------
142 
143         entities.put("OElig", "\u0152");
144         entities.put("oelig", "\u0153");
145         entities.put("Scaron", "\u0160");
146         entities.put("scaron", "\u0161");
147         entities.put("Yuml", "\u0178");
148         entities.put("circ", "\u02c6");
149         entities.put("tilde", "\u02dc");
150         entities.put("ensp", "\u2002");
151         entities.put("emsp", "\u2003");
152         entities.put("thinsp", "\u2009");
153         entities.put("zwnj", "\u200c");
154         entities.put("zwj", "\u200d");
155         entities.put("lrm", "\u200e");
156         entities.put("rlm", "\u200f");
157         entities.put("ndash", "\u2013");
158         entities.put("mdash", "\u2014");
159         entities.put("lsquo", "\u2018");
160         entities.put("rsquo", "\u2019");
161         entities.put("sbquo", "\u201a");
162         entities.put("ldquo", "\u201c");
163         entities.put("rdquo", "\u201d");
164         entities.put("bdquo", "\u201e");
165         entities.put("dagger", "\u2020");
166         entities.put("Dagger", "\u2021");
167         entities.put("permil", "\u2030");
168         entities.put("lsaquo", "\u2039");
169         entities.put("rsaquo", "\u203a");
170         entities.put("euro", "\u20ac");
171 
172         // ----------------------------------------------------------------------
173         // Symbol entities
174         // ----------------------------------------------------------------------
175 
176         entities.put("fnof", "\u0192");
177         entities.put("Alpha", "\u0391");
178         entities.put("Beta", "\u0392");
179         entities.put("Gamma", "\u0393");
180         entities.put("Delta", "\u0394");
181         entities.put("Epsilon", "\u0395");
182         entities.put("Zeta", "\u0396");
183         entities.put("Eta", "\u0397");
184         entities.put("Theta", "\u0398");
185         entities.put("Iota", "\u0399");
186         entities.put("Kappa", "\u039a");
187         entities.put("Lambda", "\u039b");
188         entities.put("Mu", "\u039c");
189         entities.put("Nu", "\u039d");
190         entities.put("Xi", "\u039e");
191         entities.put("Omicron", "\u039f");
192         entities.put("Pi", "\u03a0");
193         entities.put("Rho", "\u03a1");
194         entities.put("Sigma", "\u03a3");
195         entities.put("Tau", "\u03a4");
196         entities.put("Upsilon", "\u03a5");
197         entities.put("Phi", "\u03a6");
198         entities.put("Chi", "\u03a7");
199         entities.put("Psi", "\u03a8");
200         entities.put("Omega", "\u03a9");
201         entities.put("alpha", "\u03b1");
202         entities.put("beta", "\u03b2");
203         entities.put("gamma", "\u03b3");
204         entities.put("delta", "\u03b4");
205         entities.put("epsilon", "\u03b5");
206         entities.put("zeta", "\u03b6");
207         entities.put("eta", "\u03b7");
208         entities.put("theta", "\u03b8");
209         entities.put("iota", "\u03b9");
210         entities.put("kappa", "\u03ba");
211         entities.put("lambda", "\u03bb");
212         entities.put("mu", "\u03bc");
213         entities.put("nu", "\u03bd");
214         entities.put("xi", "\u03be");
215         entities.put("omicron", "\u03bf");
216         entities.put("pi", "\u03c0");
217         entities.put("rho", "\u03c1");
218         entities.put("sigmaf", "\u03c2");
219         entities.put("sigma", "\u03c3");
220         entities.put("tau", "\u03c4");
221         entities.put("upsilon", "\u03c5");
222         entities.put("phi", "\u03c6");
223         entities.put("chi", "\u03c7");
224         entities.put("psi", "\u03c8");
225         entities.put("omega", "\u03c9");
226         entities.put("thetasym", "\u03d1");
227         entities.put("upsih", "\u03d2");
228         entities.put("piv", "\u03d6");
229         entities.put("bull", "\u2022");
230         entities.put("hellip", "\u2026");
231         entities.put("prime", "\u2032");
232         entities.put("Prime", "\u2033");
233         entities.put("oline", "\u203e");
234         entities.put("frasl", "\u2044");
235         entities.put("weierp", "\u2118");
236         entities.put("image", "\u2111");
237         entities.put("real", "\u211c");
238         entities.put("trade", "\u2122");
239         entities.put("alefsym", "\u2135");
240         entities.put("larr", "\u2190");
241         entities.put("uarr", "\u2191");
242         entities.put("rarr", "\u2192");
243         entities.put("darr", "\u2193");
244         entities.put("harr", "\u2194");
245         entities.put("crarr", "\u21b5");
246         entities.put("lArr", "\u21d0");
247         entities.put("uArr", "\u21d1");
248         entities.put("rArr", "\u21d2");
249         entities.put("dArr", "\u21d3");
250         entities.put("hArr", "\u21d4");
251         entities.put("forall", "\u2200");
252         entities.put("part", "\u2202");
253         entities.put("exist", "\u2203");
254         entities.put("empty", "\u2205");
255         entities.put("nabla", "\u2207");
256         entities.put("isin", "\u2208");
257         entities.put("notin", "\u2209");
258         entities.put("ni", "\u220b");
259         entities.put("prod", "\u220f");
260         entities.put("sum", "\u2211");
261         entities.put("minus", "\u2212");
262         entities.put("lowast", "\u2217");
263         entities.put("radic", "\u221a");
264         entities.put("prop", "\u221d");
265         entities.put("infin", "\u221e");
266         entities.put("ang", "\u2220");
267         entities.put("and", "\u2227");
268         entities.put("or", "\u2228");
269         entities.put("cap", "\u2229");
270         entities.put("cup", "\u222a");
271         entities.put("int", "\u222b");
272         entities.put("there4", "\u2234");
273         entities.put("sim", "\u223c");
274         entities.put("cong", "\u2245");
275         entities.put("asymp", "\u2248");
276         entities.put("ne", "\u2260");
277         entities.put("equiv", "\u2261");
278         entities.put("le", "\u2264");
279         entities.put("ge", "\u2265");
280         entities.put("sub", "\u2282");
281         entities.put("sup", "\u2283");
282         entities.put("nsub", "\u2284");
283         entities.put("sube", "\u2286");
284         entities.put("supe", "\u2287");
285         entities.put("oplus", "\u2295");
286         entities.put("otimes", "\u2297");
287         entities.put("perp", "\u22a5");
288         entities.put("sdot", "\u22c5");
289         entities.put("lceil", "\u2308");
290         entities.put("rceil", "\u2309");
291         entities.put("lfloor", "\u230a");
292         entities.put("rfloor", "\u230b");
293         entities.put("lang", "\u2329");
294         entities.put("rang", "\u232a");
295         entities.put("loz", "\u25ca");
296         entities.put("spades", "\u2660");
297         entities.put("clubs", "\u2663");
298         entities.put("hearts", "\u2665");
299         entities.put("diams", "\u2666");
300         DEFAULT_ENTITIES = Collections.unmodifiableMap(entities);
301     }
302 
303     static class InputFactoryHolder {
304         static XMLInputFactory XML_INPUT_FACTORY;
305         static {
306             XMLInputFactory factory = XMLInputFactory.newFactory();
307             factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
308             XML_INPUT_FACTORY = factory;
309         }
310     }
311 
312     private boolean addDefaultEntities = true;
313 
314     private final ContentTransformer contentTransformer;
315 
316     public MetadataStaxReader() {
317         this((s, f) -> s);
318     }
319 
320     public MetadataStaxReader(ContentTransformer contentTransformer) {
321         this.contentTransformer = contentTransformer;
322     }
323 
324     /**
325      * Returns the {@link XMLInputFactory} used by this reader.
326      *
327      * @return the {@link XMLInputFactory} used by this reader.
328      */
329     public XMLInputFactory getXMLInputFactory() {
330         return InputFactoryHolder.XML_INPUT_FACTORY;
331     }
332 
333     /**
334      * Returns the state of the "add default entities" flag.
335      *
336      * @return boolean
337      */
338     public boolean getAddDefaultEntities() {
339         return addDefaultEntities;
340     } //-- boolean getAddDefaultEntities()
341 
342     /**
343      * Sets the state of the "add default entities" flag.
344      *
345      * @param addDefaultEntities a addDefaultEntities object.
346      */
347     public void setAddDefaultEntities(boolean addDefaultEntities) {
348         this.addDefaultEntities = addDefaultEntities;
349     } //-- void setAddDefaultEntities(boolean)
350 
351 
352     public Metadata read(Reader reader) throws XMLStreamException {
353         return read(reader, true);
354     }
355 
356     /**
357      * @param reader a reader object.
358      * @param strict a strict object.
359      * @throws XMLStreamException XMLStreamException if
360      * any.
361      * @return Metadata
362      */
363     public Metadata read(Reader reader, boolean strict) throws XMLStreamException {
364         StreamSource streamSource = new StreamSource(reader);
365         XMLInputFactory factory = getXMLInputFactory();
366         XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
367     return read(parser, strict);
368     } //-- Metadata read(Reader, boolean)
369 
370     public Metadata read(InputStream in) throws XMLStreamException {
371         return read(in, true);
372     }
373 
374     /**
375      * Method read.
376      *
377      * @param in a in object.
378      * @param strict a strict object.
379      * @throws XMLStreamException XMLStreamException if
380      * any.
381      * @return Metadata
382      */
383     public Metadata read(InputStream in, boolean strict) throws XMLStreamException {
384         StreamSource streamSource = new StreamSource(in);
385         XMLInputFactory factory = getXMLInputFactory();
386         XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
387         return read(parser, strict);
388     } //-- Metadata read(InputStream, boolean)
389 
390     /**
391      * Method read.
392      *
393      * @param parser a parser object.
394      * @param strict a strict object.
395      * @throws XMLStreamException XMLStreamException if
396      * any.
397      * @return Metadata
398      */
399     public Metadata read(XMLStreamReader parser, boolean strict) throws XMLStreamException {
400         Metadata metadata = null;
401         int eventType = parser.getEventType();
402         boolean parsed = false;
403         while (eventType != XMLStreamReader.END_DOCUMENT) {
404             if (eventType == XMLStreamReader.START_ELEMENT) {
405                 if (strict && ! "metadata".equals(parser.getLocalName())) {
406                     throw new XMLStreamException("Expected root element 'metadata' but found '" + parser.getName() + "'", parser.getLocation(), null);
407                 } else if (parsed) {
408                     // fallback, already expected a XMLStreamException due to invalid XML
409                     throw new XMLStreamException("Duplicated tag: 'metadata'", parser.getLocation(), null);
410                 }
411                 metadata = parseMetadata(parser, strict);
412                 parsed = true;
413             }
414             eventType = parser.next();
415         }
416         if (parsed) {
417             return metadata;
418         }
419         throw new XMLStreamException("Expected root element 'metadata' but found no element at all: invalid XML document", parser.getLocation(), null);
420     } //-- Metadata read(XMLStreamReader, boolean)
421 
422     private Metadata parseMetadata(XMLStreamReader parser, boolean strict) throws XMLStreamException {
423         String tagName = parser.getLocalName();
424         Metadata.Builder metadata = Metadata.newBuilder(true);
425         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
426             String name = parser.getAttributeLocalName(i);
427             String ns = parser.getAttributeNamespace(i);
428             String value = parser.getAttributeValue(i);
429             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
430                 // just ignore attributes with non-default namespace (for example: xsi and xml)
431             } else if ("xmlns".equals(name)) {
432                 // ignore xmlns attribute in root class, which is a reserved attribute name
433             } else if ("modelVersion".equals(name)) {
434                 metadata.modelVersion(interpolatedTrimmed(value, "modelVersion"));
435             } else {
436                 checkUnknownAttribute(parser, name, tagName, strict);
437             }
438         }
439         Set<String> parsed = new HashSet<>();
440         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
441             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
442             switch (childName) {
443                 case "groupId": {
444                     metadata.groupId(interpolatedTrimmed(nextText(parser, strict), "groupId"));
445                     break;
446                 }
447                 case "artifactId": {
448                     metadata.artifactId(interpolatedTrimmed(nextText(parser, strict), "artifactId"));
449                     break;
450                 }
451                 case "versioning": {
452                     metadata.versioning(parseVersioning(parser, strict));
453                     break;
454                 }
455                 case "version": {
456                     metadata.version(interpolatedTrimmed(nextText(parser, strict), "version"));
457                     break;
458                 }
459                 case "plugins": {
460                     List<Plugin> plugins = new ArrayList<>();
461                     while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
462                         if ("plugin".equals(parser.getLocalName())) {
463                             plugins.add(parsePlugin(parser, strict));
464                         } else {
465                             checkUnknownElement(parser, strict);
466                         }
467                     }
468                     metadata.plugins(plugins);
469                     break;
470                 }
471                 default: {
472                     checkUnknownElement(parser, strict);
473                     break;
474                 }
475             }
476         }
477         metadata.namespaceUri(parser.getNamespaceURI());
478         metadata.modelEncoding(parser.getEncoding());
479         return metadata.build();
480     }
481 
482     private Versioning parseVersioning(XMLStreamReader parser, boolean strict) throws XMLStreamException {
483         String tagName = parser.getLocalName();
484         Versioning.Builder versioning = Versioning.newBuilder(true);
485         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
486             String name = parser.getAttributeLocalName(i);
487             String ns = parser.getAttributeNamespace(i);
488             String value = parser.getAttributeValue(i);
489             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
490                 // just ignore attributes with non-default namespace (for example: xsi and xml)
491             } else {
492                 checkUnknownAttribute(parser, name, tagName, strict);
493             }
494         }
495         Set<String> parsed = new HashSet<>();
496         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
497             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
498             switch (childName) {
499                 case "latest": {
500                     versioning.latest(interpolatedTrimmed(nextText(parser, strict), "latest"));
501                     break;
502                 }
503                 case "release": {
504                     versioning.release(interpolatedTrimmed(nextText(parser, strict), "release"));
505                     break;
506                 }
507                 case "versions": {
508                     List<String> versions = new ArrayList<>();
509                     while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
510                         if ("version".equals(parser.getLocalName())) {
511                             versions.add(interpolatedTrimmed(nextText(parser, strict), "versions"));
512                         } else {
513                             checkUnknownElement(parser, strict);
514                         }
515                     }
516                     versioning.versions(versions);
517                     break;
518                 }
519                 case "lastUpdated": {
520                     versioning.lastUpdated(interpolatedTrimmed(nextText(parser, strict), "lastUpdated"));
521                     break;
522                 }
523                 case "snapshot": {
524                     versioning.snapshot(parseSnapshot(parser, strict));
525                     break;
526                 }
527                 case "snapshotVersions": {
528                     List<SnapshotVersion> snapshotVersions = new ArrayList<>();
529                     while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
530                         if ("snapshotVersion".equals(parser.getLocalName())) {
531                             snapshotVersions.add(parseSnapshotVersion(parser, strict));
532                         } else {
533                             checkUnknownElement(parser, strict);
534                         }
535                     }
536                     versioning.snapshotVersions(snapshotVersions);
537                     break;
538                 }
539                 default: {
540                     checkUnknownElement(parser, strict);
541                     break;
542                 }
543             }
544         }
545         return versioning.build();
546     }
547 
548     private Snapshot parseSnapshot(XMLStreamReader parser, boolean strict) throws XMLStreamException {
549         String tagName = parser.getLocalName();
550         Snapshot.Builder snapshot = Snapshot.newBuilder(true);
551         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
552             String name = parser.getAttributeLocalName(i);
553             String ns = parser.getAttributeNamespace(i);
554             String value = parser.getAttributeValue(i);
555             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
556                 // just ignore attributes with non-default namespace (for example: xsi and xml)
557             } else {
558                 checkUnknownAttribute(parser, name, tagName, strict);
559             }
560         }
561         Set<String> parsed = new HashSet<>();
562         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
563             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
564             switch (childName) {
565                 case "timestamp": {
566                     snapshot.timestamp(interpolatedTrimmed(nextText(parser, strict), "timestamp"));
567                     break;
568                 }
569                 case "buildNumber": {
570                     snapshot.buildNumber(getIntegerValue(interpolatedTrimmed(nextText(parser, strict), "buildNumber"), "buildNumber", parser, strict, 0));
571                     break;
572                 }
573                 case "localCopy": {
574                     snapshot.localCopy(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "localCopy"), "localCopy", parser, false));
575                     break;
576                 }
577                 default: {
578                     checkUnknownElement(parser, strict);
579                     break;
580                 }
581             }
582         }
583         return snapshot.build();
584     }
585 
586     private SnapshotVersion parseSnapshotVersion(XMLStreamReader parser, boolean strict) throws XMLStreamException {
587         String tagName = parser.getLocalName();
588         SnapshotVersion.Builder snapshotVersion = SnapshotVersion.newBuilder(true);
589         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
590             String name = parser.getAttributeLocalName(i);
591             String ns = parser.getAttributeNamespace(i);
592             String value = parser.getAttributeValue(i);
593             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
594                 // just ignore attributes with non-default namespace (for example: xsi and xml)
595             } else {
596                 checkUnknownAttribute(parser, name, tagName, strict);
597             }
598         }
599         Set<String> parsed = new HashSet<>();
600         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
601             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
602             switch (childName) {
603                 case "classifier": {
604                     snapshotVersion.classifier(interpolatedTrimmed(nextText(parser, strict), "classifier"));
605                     break;
606                 }
607                 case "extension": {
608                     snapshotVersion.extension(interpolatedTrimmed(nextText(parser, strict), "extension"));
609                     break;
610                 }
611                 case "value": {
612                     snapshotVersion.version(interpolatedTrimmed(nextText(parser, strict), "value"));
613                     break;
614                 }
615                 case "updated": {
616                     snapshotVersion.updated(interpolatedTrimmed(nextText(parser, strict), "updated"));
617                     break;
618                 }
619                 default: {
620                     checkUnknownElement(parser, strict);
621                     break;
622                 }
623             }
624         }
625         return snapshotVersion.build();
626     }
627 
628     private Plugin parsePlugin(XMLStreamReader parser, boolean strict) throws XMLStreamException {
629         String tagName = parser.getLocalName();
630         Plugin.Builder plugin = Plugin.newBuilder(true);
631         for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
632             String name = parser.getAttributeLocalName(i);
633             String ns = parser.getAttributeNamespace(i);
634             String value = parser.getAttributeValue(i);
635             if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
636                 // just ignore attributes with non-default namespace (for example: xsi and xml)
637             } else {
638                 checkUnknownAttribute(parser, name, tagName, strict);
639             }
640         }
641         Set<String> parsed = new HashSet<>();
642         while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
643             String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
644             switch (childName) {
645                 case "name": {
646                     plugin.name(interpolatedTrimmed(nextText(parser, strict), "name"));
647                     break;
648                 }
649                 case "prefix": {
650                     plugin.prefix(interpolatedTrimmed(nextText(parser, strict), "prefix"));
651                     break;
652                 }
653                 case "artifactId": {
654                     plugin.artifactId(interpolatedTrimmed(nextText(parser, strict), "artifactId"));
655                     break;
656                 }
657                 default: {
658                     checkUnknownElement(parser, strict);
659                     break;
660                 }
661             }
662         }
663         return plugin.build();
664     }
665 
666 
667     private String checkDuplicate(String tagName, XMLStreamReader parser, Set<String> parsed) throws XMLStreamException {
668         if (!parsed.add(tagName)) {
669             throw new XMLStreamException("Duplicated tag: '" + tagName + "'", parser.getLocation(), null);
670         }
671         return tagName;
672     }
673 
674     /**
675      * Method checkUnknownAttribute.
676      *
677      * @param parser a parser object.
678      * @param strict a strict object.
679      * @param tagName a tagName object.
680      * @param attribute a attribute object.
681      * @throws XMLStreamException XMLStreamException if
682      * any.
683      * @throws IOException IOException if any.
684      */
685     private void checkUnknownAttribute(XMLStreamReader parser, String attribute, String tagName, boolean strict) throws XMLStreamException {
686         // strictXmlAttributes = true for model: if strict == true, not only elements are checked but attributes too
687         if (strict) {
688             throw new XMLStreamException("Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser.getLocation(), null);
689         }
690     } //-- void checkUnknownAttribute(XMLStreamReader, String, String, boolean)
691 
692     /**
693      * Method checkUnknownElement.
694      *
695      * @param parser a parser object.
696      * @param strict a strict object.
697      * @throws XMLStreamException XMLStreamException if
698      * any.
699      * @throws IOException IOException if any.
700      */
701     private void checkUnknownElement(XMLStreamReader parser, boolean strict) throws XMLStreamException {
702         if (strict) {
703             throw new XMLStreamException("Unrecognised tag: '" + parser.getName() + "'", parser.getLocation(), null);
704         }
705 
706         for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
707             int eventType = nextTag(parser);
708             if (eventType == XMLStreamReader.START_ELEMENT) {
709                 unrecognizedTagCount++;
710             } else if (eventType == XMLStreamReader.END_ELEMENT) {
711                 unrecognizedTagCount--;
712             }
713         }
714     } //-- void checkUnknownElement(XMLStreamReader, boolean)
715 
716     /**
717      * Method getTrimmedValue.
718      *
719      * @param s a s object.
720      * @return String
721      */
722     private String getTrimmedValue(String s) {
723         if (s != null) {
724             s = s.trim();
725         }
726         return s;
727     } //-- String getTrimmedValue(String)
728 
729     /**
730      * Method interpolatedTrimmed.
731      *
732      * @param value a value object.
733      * @param context a context object.
734      * @return String
735      */
736     private String interpolatedTrimmed(String value, String context) {
737         return getTrimmedValue(contentTransformer.transform(value, context));
738     } //-- String interpolatedTrimmed(String, String)
739 
740     /**
741      * Method nextTag.
742      *
743      * @param parser a parser object.
744      * @throws IOException IOException if any.
745      * @throws XMLStreamException XMLStreamException if
746      * any.
747      * @return int
748      */
749     private int nextTag(XMLStreamReader parser) throws XMLStreamException {
750         while (true) {
751             int next = parser.next();
752             switch (next) {
753                 case XMLStreamReader.SPACE:
754                 case XMLStreamReader.COMMENT:
755                 case XMLStreamReader.PROCESSING_INSTRUCTION:
756                 case XMLStreamReader.CDATA:
757                 case XMLStreamReader.CHARACTERS:
758                     continue;
759                 case XMLStreamReader.START_ELEMENT:
760                 case XMLStreamReader.END_ELEMENT:
761                     return next;
762             }
763         }
764     } //-- int nextTag(XMLStreamReader)
765 
766     private String nextText(XMLStreamReader parser, boolean strict) throws XMLStreamException {
767         int eventType = parser.getEventType();
768         if (eventType != XMLStreamReader.START_ELEMENT) {
769             throw new XMLStreamException("parser must be on START_ELEMENT to read next text", parser.getLocation(), null);
770         }
771         eventType = parser.next();
772         StringBuilder result = new StringBuilder();
773         while (true) {
774             if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
775                 result.append(parser.getText());
776             } else if (eventType == XMLStreamReader.ENTITY_REFERENCE) {
777                 String val = null;
778                 if (strict) {
779                     throw new XMLStreamException("Entities are not supported in strict mode", parser.getLocation(), null);
780                 } else if (addDefaultEntities) {
781                     val = DEFAULT_ENTITIES.get(parser.getLocalName());
782                 }
783                 if (val != null) {
784                     result.append(val);
785                 } else {
786                     result.append("&").append(parser.getLocalName()).append(";");
787                 }
788             } else if (eventType != XMLStreamReader.COMMENT) {
789                 break;
790             }
791             eventType = parser.next();
792         }
793         if (eventType != XMLStreamReader.END_ELEMENT) {
794             throw new XMLStreamException(
795                 "TEXT must be immediately followed by END_ELEMENT and not " + eventType /*TODO: TYPES[eventType]*/, parser.getLocation(), null);
796         }
797         return result.toString();
798     }
799 
800     private XmlNode buildXmlNode(XMLStreamReader parser) throws XMLStreamException {
801         return XmlNodeStaxBuilder.build(parser);
802     }
803 
804     /**
805      * Method getBooleanValue.
806      *
807      * @param s a s object.
808      * @param defaultValue a defaultValue object.
809      * @param parser a parser object.
810      * @param attribute a attribute object.
811      * @throws XMLStreamException XMLStreamException if
812      * any.
813      * @return boolean
814      */
815     private boolean getBooleanValue(String s, String attribute, XMLStreamReader parser, boolean defaultValue) throws XMLStreamException {
816         if (s != null && s.length() != 0) {
817             return Boolean.valueOf(s).booleanValue();
818         }
819         return defaultValue;
820     } //-- boolean getBooleanValue(String, String, XMLStreamReader, String)
821 
822     /**
823      * Method getIntegerValue.
824      *
825      * @param s a s object.
826      * @param strict a strict object.
827      * @param parser a parser object.
828      * @param attribute a attribute object.
829      * @throws XMLStreamException XMLStreamException if
830      * any.
831      * @return int
832      */
833     private int getIntegerValue(String s, String attribute, XMLStreamReader parser, boolean strict, int defaultValue) throws XMLStreamException {
834         if (s != null) {
835             try {
836                 return Integer.valueOf(s).intValue();
837             } catch (NumberFormatException nfe) {
838                 if (strict) {
839                     throw new XMLStreamException("Unable to parse element '" + attribute + "', must be an integer", parser.getLocation(), nfe);
840                 }
841             }
842         }
843         return defaultValue;
844     } //-- int getIntegerValue(String, String, XMLStreamReader, boolean)
845 
846     public static interface ContentTransformer {
847         /**
848          * Interpolate the value read from the xpp3 document
849          * @param source The source value
850          * @param fieldName A description of the field being interpolated. The implementation may use this to
851          *                           log stuff.
852          * @return The interpolated value.
853          */
854         String transform(String source, String fieldName);
855     }
856 
857 }