/*
* Copyright 2006-2012 The Scriptella Project Team.
*
* 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 scriptella.configuration;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import scriptella.expression.PropertiesSubstitutor;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Represents XML element
*
* @author Fyodor Kupolov
* @version 1.0
*/
public class XmlElement {
private Element element;
private URL documentUrl;
private PropertiesSubstitutor substitutor;
public XmlElement(Element element, URL documentUrl, PropertiesSubstitutor substitutor) {
this.element = element;
this.documentUrl = documentUrl;
this.substitutor = substitutor;
}
public XmlElement(Element element, XmlElement parent) {
this(element, parent.documentUrl, parent.substitutor);
}
public String getTagName() {
return element.getTagName();
}
public Element getElement() {
return element;
}
public URL getDocumentUrl() {
return documentUrl;
}
protected List<XmlElement> getChildren() {
return asList(element.getChildNodes());
}
public String getXPath() {
List<String> l = new ArrayList<String>();
Node cur = element;
StringBuilder tmp = new StringBuilder();
String nearestIDSelector = null;
while (!(cur instanceof Document)) {
String id = ((Element) cur).getAttribute("id");
if (!id.equals("")) {
nearestIDSelector = "id(\"" + id + "\")";
break;
}
int pos = 1;
Node sib = cur;
final String curTagName = ((Element) cur).getTagName();
while (sib != null) {
sib = sib.getPreviousSibling();
if ((sib != null) && sib instanceof Element) {
Element ee = (Element) sib;
if (curTagName.equals(ee.getTagName())) {
pos++;
}
}
}
tmp.setLength(0);
tmp.append(curTagName);
cur = cur.getParentNode();
if (!(cur instanceof Document)) {
tmp.append('[');
tmp.append(pos);
tmp.append(']');
}
l.add(tmp.toString());
}
StringBuilder res = new StringBuilder(100);
if (nearestIDSelector != null) {
res.append(nearestIDSelector);
}
for (int i = l.size() - 1; i >= 0; i--) {
res.append('/');
res.append(l.get(i));
}
return res.toString();
}
public List<XmlElement> getChildren(final String name) {
List<XmlElement> res = new ArrayList<XmlElement>();
Node node = element.getFirstChild();
while (node != null) {
if (node instanceof Element) {
if (name.equals(((Element) node).getTagName())) {
res.add(new XmlElement((Element) node, this));
}
}
node = node.getNextSibling();
}
return res;
}
public List<XmlElement> getChildren(final Set<String> names) {
List<XmlElement> res = new ArrayList<XmlElement>();
Node node = element.getFirstChild();
while (node != null) {
if (node instanceof Element) {
if (names.contains(((Element) node).getTagName())) {
res.add(new XmlElement((Element) node, this));
}
}
node = node.getNextSibling();
}
return res;
}
public XmlElement getChild(final String name) {
Node node = element.getFirstChild();
while (node != null) {
if (node instanceof Element) {
if (name.equals(((Element) node).getTagName())) {
return new XmlElement((Element) node, this);
}
}
node = node.getNextSibling();
}
return null;
}
protected List<XmlElement> asList(final NodeList list) {
List<XmlElement> result = new ArrayList<XmlElement>();
Node node = element.getFirstChild();
while (node != null) {
if (node instanceof Element) {
result.add(new XmlElement((Element) node, this));
}
node = node.getNextSibling();
}
return result;
}
/**
* Gets the value of attribute.
* <p>Additionally property {@link #expandProperties(String) expansion} is performed.
* @param attribute attribute name.
* @return value of the attribute or null if attribute is absent or has empty value.
*/
public String getAttribute(final String attribute) {
final String a = element.getAttribute(attribute);
return ((a != null) && (a.length() == 0)) ? null : expandProperties(a);
}
/**
* Returns the value of boolean attribute.
* @param attribute attribute name.
* @param defaultValue default value to use if attribute value unspecified.
* @see #getAttribute(String)
*/
protected boolean getBooleanAttribute(final String attribute,
final boolean defaultValue) {
final String a = getAttribute(attribute);
if (a == null) {
return defaultValue;
}
if ("true".equalsIgnoreCase(a) || "1".equalsIgnoreCase(a) ||
"on".equalsIgnoreCase(a) || "yes".equalsIgnoreCase(a)) {
return true;
}
if ("false".equalsIgnoreCase(a) || "0".equalsIgnoreCase(a) ||
"off".equalsIgnoreCase(a) || "no".equalsIgnoreCase(a)) {
return false;
}
throw new ConfigurationException("Unrecognized value '" + a +
"' of boolean attribute " + attribute +
". Valid values: yes/no, true/false, 1/0, on/off", this);
}
/**
* Expands properties in a string.
* @param s string to expand properties.
* @return string with substituted properties.
*/
public String expandProperties(final String s) {
return substitutor.substitute(s);
}
}