/*
* Copyright (c) 2010-2013 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.util;
import java.util.ArrayList;
import java.util.List;
import javax.xml.XMLConstants;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* @author semancik
*
*/
public class UglyHacks {
// We hope that nobody will chose a crazy name like this. We don't want to use namespaces
// here as that may be messed up as well.
private static final String FORTIFIED_NAMESPACE_DECLARATIONS_ELEMENT_NAME = "FORtiFIed__xmlNS";
private static final char FORTIFIED_NAMESPACE_DECLARATIONS_SEPARATOR = ' ';
public static String forceXsiNsDeclaration(String originalXml) {
int iOpeningBracket = -1;
while (true) {
iOpeningBracket = originalXml.indexOf('<', iOpeningBracket+1);
if (iOpeningBracket < 0) {
// No element ?
return originalXml;
}
if (Character.isLetter(originalXml.charAt(iOpeningBracket+1))) {
break;
}
// Processing instruction, skip it
}
int iClosingBracket = originalXml.indexOf('>', iOpeningBracket);
if (iClosingBracket < 0) {
// Element not closed?
return originalXml;
}
String firstElement = originalXml.substring(iOpeningBracket, iClosingBracket);
// Not perfect, but should be good enough. All this is a hack anyway
if (firstElement.indexOf("xmlns:xsi") >= 0) {
// Already has xsi declaration
return originalXml;
}
int iEndOfElementName = iOpeningBracket;
while (iEndOfElementName < iClosingBracket) {
char ch = originalXml.charAt(iEndOfElementName);
if (ch == ' ' || ch == '>') {
break;
}
iEndOfElementName++;
}
StringBuilder sb = new StringBuilder();
sb.append(originalXml.substring(0, iEndOfElementName));
sb.append(" xmlns:xsi='");
sb.append(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
sb.append("'");
sb.append(originalXml.substring(iEndOfElementName));
return sb.toString();
}
public static void fortifyNamespaceDeclarations(Node node) {
DomElementVisitor visitor = new DomElementVisitor() {
@Override
public void visit(Element element) {
fortifyNamespaceDeclarationsSingleElement(element);
}
};
DomVisitorUtil.visitElements(node, visitor);
}
public static void fortifyNamespaceDeclarationsSingleElement(Element element) {
List<String> xmlnss = new ArrayList<String>();
NamedNodeMap attributes = element.getAttributes();
for(int i=0; i<attributes.getLength(); i++) {
Attr attr = (Attr)attributes.item(i);
if (DOMUtil.isNamespaceDefinition(attr)) {
String prefix = DOMUtil.getNamespaceDeclarationPrefix(attr);
String namespace = DOMUtil.getNamespaceDeclarationNamespace(attr);
xmlnss.add(prefix + "=" + namespace);
}
}
String fortifiedXmlnss = StringUtils.join(xmlnss, FORTIFIED_NAMESPACE_DECLARATIONS_SEPARATOR);
element.setAttribute(FORTIFIED_NAMESPACE_DECLARATIONS_ELEMENT_NAME, fortifiedXmlnss);
}
public static void unfortifyNamespaceDeclarations(Node node) {
DomElementVisitor visitor = new DomElementVisitor() {
@Override
public void visit(Element element) {
unfortifyNamespaceDeclarationsSingleElement(element);
}
};
DomVisitorUtil.visitElements(node, visitor);
}
public static void unfortifyNamespaceDeclarationsSingleElement(Element element) {
String fortifiedXmlnss = element.getAttribute(FORTIFIED_NAMESPACE_DECLARATIONS_ELEMENT_NAME);
if (element.hasAttribute(FORTIFIED_NAMESPACE_DECLARATIONS_ELEMENT_NAME)) {
element.removeAttribute(FORTIFIED_NAMESPACE_DECLARATIONS_ELEMENT_NAME);
}
if (StringUtils.isBlank(fortifiedXmlnss)) {
return;
}
String[] xmlnss = StringUtils.split(fortifiedXmlnss, FORTIFIED_NAMESPACE_DECLARATIONS_SEPARATOR);
for (String xmlns: xmlnss) {
String[] prefixAndUrl = StringUtils.split(xmlns, "=", 2);
String prefix = prefixAndUrl[0];
String url = prefixAndUrl[1];
if (!DOMUtil.hasNamespaceDeclarationForPrefix(element, prefix)) {
DOMUtil.setNamespaceDeclaration(element, prefix, url);
}
}
}
}