String encoding = element.getAttributeValue("encoding");
String href = element.getAttributeValue("href");
// empty string href is same as no href attribute
if ("".equals(href)) href = null;
ParentNode parent = element.getParent();
String base = element.getBaseURI();
URL baseURL = null;
try {
baseURL = new URL(base);
}
catch (MalformedURLException ex) {
// don't use base
}
URL url = null;
try {
// xml:base attributes added to maintain the
// base URI should not have fragment IDs
if (baseURL != null && href != null) {
url = absolutize(baseURL, href);
}
else if (href != null) {
try {
testURISyntax(href);
url = new URL(href);
}
catch (MalformedURIException ex) {
if (baseURL == null) {
throw new BadHrefAttributeException(
"Could not resolve relative URI " + href
+ " because the xi:include element does"
+ " not have a base URI.", href);
}
throw new BadHrefAttributeException("Illegal IRI in href attribute", href);
}
}
String accept = element.getAttributeValue("accept");
checkHeader(accept);
String acceptLanguage = element.getAttributeValue("accept-language");
checkHeader(acceptLanguage);
if (parse.equals("xml")) {
String parentLanguage = "";
if (parent instanceof Element) {
parentLanguage = getXMLLangValue((Element) parent);
}
Nodes replacements;
if (url != null) {
replacements = downloadXMLDocument(url,
xpointer, builder, baseURLs, accept, acceptLanguage, parentLanguage);
// Add base URIs. Base URIs added by XInclusion require
// the element to maintain the same base URI as it had
// in the original document. Since its base URI in the
// original document does not contain a fragment ID,
// therefore its base URI after inclusion shouldn't,
// and this special case is unnecessary. Base URI fixup
// should not add the fragment ID.
for (int i = 0; i < replacements.size(); i++) {
Node child = replacements.get(i);
if (child instanceof Element) {
String noFragment = child.getBaseURI();
if (noFragment.indexOf('#') >= 0) {
noFragment = noFragment.substring(
0, noFragment.indexOf('#'));
}
Element baseless = (Element) child;
// parent is null here; need to get real parent
String parentBase = parent.getBaseURI();
if (parentBase != null && ! "".equals(parentBase)) {
parentBase = getDirectoryBase(parentBase);
}
if (noFragment.startsWith(parentBase)) {
noFragment = noFragment.substring(parentBase.length());
}
Attribute baseAttribute = new Attribute(
"xml:base",
"http://www.w3.org/XML/1998/namespace",
noFragment
);
baseless.addAttribute(baseAttribute);
}
}
}
else {
Document parentDoc = element.getDocument();
if (parentDoc == null) {
parentDoc = originalDoc;
}
Nodes originals = XPointer.query(parentDoc, xpointer);
replacements = new Nodes();
for (int i = 0; i < originals.size(); i++) {
Node original = originals.get(i);
// current implementation of XPointer never returns non-elements
if (contains((Element) original, element)) {
throw new InclusionLoopException(
"Element tried to include itself"
);
}
Node copy = original.copy();
replacements.append(copy);
}
replacements = resolveXPointerSelection(
replacements, builder, baseURLs, parentDoc);
}
// Will fail if we're replacing the root element with
// a node list containing zero or multiple elements,
// but that should fail. However, I may wish to
// adjust the type of exception thrown. This is only
// relevant if I add support for the xpointer scheme
// since otherwise you can only point at one element
// or document.
if (parent instanceof Element) {
int position = parent.indexOf(element);
for (int i = 0; i < replacements.size(); i++) {
Node child = replacements.get(i);
parent.insertChild(child, position+i);
}
element.detach();
}
else { // root element needs special treatment
// I am assuming here that it is not possible
// for parent to be null. I think this is true
// in the current version, but it could change
// if I made it possible to directly resolve an
// element or a Nodes.
Document doc = (Document) parent;
int i = 0;
// prolog and root
while (true) {
Node child = replacements.get(i);
i++;
if (child instanceof Element) {
doc.setRootElement((Element) child);
break;
}
else {
doc.insertChild(
child, doc.indexOf(element)
);
}
}
// epilog
Element root = doc.getRootElement();
int position = doc.indexOf(root);
for (int j=i; j < replacements.size(); j++) {
doc.insertChild(
replacements.get(j), position+1+j-i
);
}
}
}
else if (parse.equals("text")) {
Nodes replacements
= downloadTextDocument(url, encoding, builder, accept, acceptLanguage);
for (int j = 0; j < replacements.size(); j++) {
Node replacement = replacements.get(j);
if (replacement instanceof Attribute) {
((Element) parent).addAttribute((Attribute) replacement);
}
else {
parent.insertChild(replacement, parent.indexOf(element));
}
}
parent.removeChild(element);
}
else {
throw new BadParseAttributeException(
"Bad value for parse attribute: " + parse,
element.getDocument().getBaseURI());