private void processInclude()

in src/main/java/org/apache/maven/xinclude/stax/XIncludeStreamReader.java [145:467]


    private void processInclude() throws XMLStreamException {

        Location startLocation = this.getLocation();

        Element node;
        try {
            Document doc =
                    DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            DOMResult res = new DOMResult(doc);
            XMLEventWriter xew = outputFactory.createXMLEventWriter(res);
            XMLEventReader xer = factory.createXMLEventReader(new FragmentReader(getDelegate()));
            xew.add(xer);
            node = doc.getDocumentElement();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        String href = getAttribute(node, "href");
        String parse = getAttribute(node, "parse");
        String xpointer = getAttribute(node, "xpointer");
        String fragid = getAttribute(node, "fragid");
        String setXmlId = getAttribute(node, "set-xml-id");
        String encoding = getAttribute(node, "encoding");

        IOException resourceError = null;

        if (href == null) {
            if (xpointer == null && fragid == null) {
                throw new XMLStreamException("xpointer or fragid must be used as href is null");
            }
            href = "";
        } else if (href.contains("#")) {
            throw new XMLStreamException("fragment identifiers must not be used in href: " + href);
        }
        URI hrefUri;
        try {
            hrefUri = new URI(href);
        } catch (URISyntaxException e) {
            throw new XMLStreamException("invalid syntax for href: " + href, e);
        }

        Source input;
        String currentLocation = xmlBases.peek();
        XMLResolver r = factory.getXMLResolver();
        Object o = r != null ? r.resolveEntity(null, href, currentLocation, null) : null;
        if (o instanceof URI) {
            try {
                o = new Stax2URLSource(((URI) o).toURL());
            } catch (MalformedURLException e) {
                throw new XMLStreamException(e);
            }
        }
        if (o != null && !(o instanceof Source)) {
            throw new XMLStreamException(
                    "Unsupported input of class " + o.getClass().getName());
        }
        if (o == null) {
            resourceError = new IOException("Unable to load resource: " + href);
        }
        input = (Source) o;

        boolean isXml = false;
        boolean isText = false;
        if (resourceError == null) {
            if (parse == null || "xml".equals(parse) || "application/xml".equals(parse) || parse.endsWith("+xml")) {
                isXml = true;
            } else if ("text".equals(parse) || parse.startsWith("text/")) {
                isText = true;
                if (xpointer != null) {
                    throw new XMLStreamException("xpointer cannot be used with text parsing");
                }
            } else {
                resourceError = new IOException("Unsupported media type: " + parse);
            }
        }

        boolean fallback = true;
        if (resourceError == null && isXml) {
            boolean reportPrologWs = (boolean) factory.getProperty(XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE);
            if (reportPrologWs) {
                factory.setProperty(XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE, false);
            }
            XMLStreamReader reader = factory.createXMLStreamReader(input);
            String pointer = xpointer != null ? xpointer : fragid;
            try {
                Document doc = DocumentBuilderFactory.newInstance()
                        .newDocumentBuilder()
                        .newDocument();
                DOMResult res = new DOMResult(doc);
                XMLEventWriter xew = outputFactory.createXMLEventWriter(res);
                XMLEventReader xer = factory.createXMLEventReader(reader);
                DTD dtd = null;
                while (xer.hasNext()) {
                    XMLEvent event = xer.nextEvent();
                    if (event instanceof DTD) {
                        dtd = (DTD) event;
                    } else {
                        xew.add(event);
                    }
                }

                Element resNode;
                if (pointer != null) {
                    DOMXMLElementEvaluator evaluator = new DOMXMLElementEvaluator(
                            new XPointer(pointer),
                            doc.getDocumentElement(),
                            dtd != null ? (DTDSubset) dtd.getProcessedDTD() : null);
                    resNode = evaluator.evaluateElement();
                } else {
                    resNode = doc.getDocumentElement();
                }

                if (resNode != null) {
                    // xml:lang fix
                    String curLang = this.xmlLangs.peek();
                    String impLang = "";

                    Element p = resNode;
                    while (p != null) {
                        Attr attr = p.getAttributeNodeNS(XML_NS_URI, "lang");
                        if (attr != null) {
                            impLang = attr.getValue();
                            break;
                        }
                        Node np = p.getParentNode();
                        p = np instanceof Element ? (Element) np : null;
                    }
                    if (!Objects.equals(curLang, impLang)) {
                        resNode.setAttributeNS(XML_NS_URI, "xml:lang", impLang);
                    }
                    resNode.setAttributeNS(XML_NS_URI, "xml:base", input.getSystemId());

                    NamespaceContext context =
                            this.contextStack.peek().getReader().getNamespaceContext();
                    Map<String, String> namespaces = getAllNamespaces(resNode.getParentNode());
                    for (Map.Entry<String, String> entry : namespaces.entrySet()) {
                        String prefix = entry.getKey();
                        String uri = entry.getValue();
                        if (context != null
                                && context.getNamespaceURI(prefix) != null
                                && !uri.equals(context.getNamespaceURI(prefix))) {
                            resNode.setAttributeNS(
                                    XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
                                    prefix.isEmpty() ? "xmlns" : "xmlns:" + prefix,
                                    uri);
                        }
                    }

                    NamedNodeMap attrs = node.getAttributes();
                    for (int i = 0; i < attrs.getLength(); i++) {
                        Attr att = (Attr) attrs.item(i);
                        String ns = att.getNamespaceURI();
                        if (ns != null && !XML_NS_URI.equals(ns)) {
                            if ("http://www.w3.org/2001/XInclude/local-attributes".equals(ns)) {
                                resNode.setAttribute(att.getLocalName(), att.getValue());
                            } else {
                                resNode.setAttributeNS(ns, att.getPrefix() + ":" + att.getLocalName(), att.getValue());
                            }
                        }
                    }
                    if (setXmlId != null) {
                        resNode.setAttributeNS(XML_NS_URI, "xml:id", setXmlId);
                    }

                    XMLStreamReader sr = factory.createXMLStreamReader(new DOMSource(resNode));
                    pushContext(input.getSystemId(), sr);
                    fallback = false;
                }
            } catch (InvalidXPointerException | ParserConfigurationException e) {
                throw new XMLStreamException(e);
            }
        } else if (resourceError == null && isText) {
            try {
                StringWriter sw = new StringWriter();
                Reader reader;
                if (input instanceof StreamSource) {
                    StreamSource ss = (StreamSource) input;
                    reader = ss.getReader();
                    if (reader == null) {
                        InputStream is = ss.getInputStream();
                        reader = new InputStreamReader(is, encoding != null ? encoding : "UTF-8");
                    }
                } else if (input instanceof Stax2Source) {
                    Stax2Source ss = (Stax2Source) input;
                    reader = ss.constructReader();
                    if (reader == null) {
                        InputStream is = ss.constructInputStream();
                        reader = new InputStreamReader(is, encoding != null ? encoding : "UTF-8");
                    }
                } else {
                    throw new XMLStreamException(
                            "Unsupported source of class " + input.getClass().getName());
                }
                transferTo(reader, sw);
                String include;
                if (fragid != null) {
                    String scheme;
                    String integrity;
                    int scIdx = fragid.indexOf(';');
                    if (scIdx > 0) {
                        scheme = fragid.substring(0, scIdx);
                        integrity = fragid.substring(scIdx + 1);
                    } else {
                        scheme = fragid;
                        integrity = "";
                    }
                    if (scheme.startsWith("char=")) {
                        String str = scheme.substring("char=".length());
                        int idx = str.indexOf(',');
                        int min, max;
                        if (idx >= 0) {
                            min = idx == 0 ? 0 : Integer.parseInt(str.substring(0, idx));
                            max = idx == str.length() - 1 ? str.length() - 1 : Integer.parseInt(str.substring(idx + 1));
                        } else {
                            min = Integer.parseInt(str);
                            max = min;
                        }
                        include = sw.toString().substring(min, max);
                    } else if (scheme.startsWith("line=")) {
                        String str = scheme.substring("line=".length());
                        int idx = str.indexOf(',');
                        int min, max;
                        if (idx >= 0) {
                            min = idx == 0 ? 0 : Integer.parseInt(str.substring(0, idx));
                            max = idx == str.length() - 1 ? str.length() - 1 : Integer.parseInt(str.substring(idx + 1));
                        } else {
                            min = Integer.parseInt(str);
                            max = min;
                        }
                        BufferedReader br = new BufferedReader(new StringReader(sw.toString()));
                        include = br.lines().skip(min).limit(max - min).collect(Collectors.joining("\n", "", "\n"));
                    } else {
                        throw new XMLStreamException("Unsupported text scheme in fragid: " + fragid);
                    }
                    if (!integrity.isEmpty()) {
                        String charset = null;
                        int idx = integrity.indexOf(',');
                        if (idx >= 0) {
                            charset = integrity.substring(idx + 1);
                            integrity = integrity.substring(0, idx);
                            if (integrity.startsWith("length=")) {
                                // TODO: implement
                            } else if (integrity.startsWith("md5=")) {
                                // TODO: implement
                            } else {
                                throw new XMLStreamException("Unsupported text integrity in fragid: " + fragid);
                            }
                        }
                    }
                } else {
                    include = sw.toString();
                }

                StreamReaderDelegate sr = new StreamReaderDelegate() {
                    int state = 0;

                    @Override
                    protected XMLStreamReader getDelegate() {
                        return null;
                    }

                    @Override
                    public int next() throws XMLStreamException {
                        state++;
                        return getEventType();
                    }

                    @Override
                    public int getEventType() {
                        switch (state) {
                            case 0:
                                return START_ELEMENT;
                            case 1:
                                return CHARACTERS;
                        }
                        return END_DOCUMENT;
                    }

                    @Override
                    public String getText() {
                        return include;
                    }

                    @Override
                    public Location getLocation() {
                        return XMLStreamLocation2.NOT_AVAILABLE;
                    }
                };
                pushContext(input.getSystemId(), sr);
                fallback = false;
            } catch (IOException e) {
                resourceError = e;
            }
        }

        // now skip fallback elements
        boolean hasFallback = false;
        for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
            if (!(child instanceof Element)) {
                continue;
            }
            if (XINCLUDE_NAMESPACE.equals(child.getNamespaceURI())) {
                if (XINCLUDE_FALLBACK.equals(child.getLocalName())) {
                    if (hasFallback) {
                        throw new XMLStreamException("One one xi:fallback element can be present", startLocation);
                    }
                    hasFallback = true;
                    if (fallback) {
                        XMLStreamReader sr = factory.createXMLStreamReader(new DOMSource(child));
                        sr.nextTag(); // the fallback
                        sr.next(); // next
                        sr = new FragmentReader(sr);
                        pushContext(currentLocation, sr);
                        break;
                    }
                } else {
                    throw new XMLStreamException(
                            "Element " + child.getLocalName() + " cannot be present inside the include element",
                            startLocation);
                }
            }
        }
    }