package org.openrosa.client.xforms;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;
/**
* Utility methods used when manipulating xml documents.
*
* @author daniel
*
*/
public class XmlUtil {
/**
* All methods in this class are static and hence we expect no external
* Instantiation of this class.
*/
private XmlUtil(){
}
/**
* Checks if a node name equals a particular name, regardless of prefix.
* NOTE: If checking names containing subsets of others using case or if else statements,
* start with one which is not contained by others.
* e.g "itemset" should be before "item".
*
* @param nodeName the node name.
* @param name the name to compare with.
* @return true if they are the same, else false.
*/
public static boolean nodeNameEquals(String nodeName, String name){
return nodeName.equals(name) || nodeName.contains(":"+name);
}
public static String getItextTextValue(Node node){
int numOfEntries = node.getChildNodes().getLength();
if(numOfEntries == 0){ return null; }
String s = "";
for (int i = 0; i < numOfEntries; i++) {
Node child = node.getChildNodes().item(i);
if (child.getNodeType() == Node.TEXT_NODE){
s += child.getNodeValue();
}else if (child.getNodeType() == Node.ELEMENT_NODE){
((Element)child).removeAttribute("xmlns");
s += ((Element)child).toString();
}
}
return s;
}
/**
* Gets the text value of a node.
*
* @param node the node whose text value to get.
* @return the text value.
*/
public static String getTextValue(Node node){
int numOfEntries = node.getChildNodes().getLength();
for (int i = 0; i < numOfEntries; i++) {
if (node.getChildNodes().item(i).getNodeType() == Node.TEXT_NODE){
//These iterations are for particularly firefox which when comes accross
//text bigger than 4096, splits it into multiple adjacent text nodes
//each not exceeding the maximum 4096. This is as of 04/04/2009
//and for Firefox version 3.0.8
String s = "";
for(int index = i; index<numOfEntries; index++){
Node currentNode = node.getChildNodes().item(index);
String value = currentNode.getNodeValue();
if(currentNode.getNodeType() == Node.TEXT_NODE && value != null)
s += value;
else
break;
}
return s.trim();
//return node.getChildNodes().item(i).getNodeValue();
}
if(node.getChildNodes().item(i).getNodeType() == Node.ELEMENT_NODE){
String val = getTextValue((Element)node.getChildNodes().item(i));
if(val != null)
return val.trim();
}
}
return null;
}
/**
* Sets the text value of a node.
*
* @param node the node whose text value to set.
* @param value the text value.
* @return true if the value was set successfully, else false.
*/
public static boolean setTextNodeValue(Element node, String value){
if(node == null)
return false;
int numOfEntries = node.getChildNodes().getLength();
for (int i = 0; i < numOfEntries; i++) {
if (node.getChildNodes().item(i).getNodeType() == Node.TEXT_NODE){
node.getChildNodes().item(i).setNodeValue(value);
return true;
}
if(node.getChildNodes().item(i).getNodeType() == Node.ELEMENT_NODE){
if(setTextNodeValue((Element)node.getChildNodes().item(i),value))
return true;
}
}
if(numOfEntries == 0){
node.appendChild(node.getOwnerDocument().createTextNode(value));
return true;
}
return false;
}
/*public static boolean setTextValue(Node node, String value){
if(node == null)
return false;
int numOfEntries = node.getChildNodes().getLength();
for (int i = 0; i < numOfEntries; i++) {
if (node.getChildNodes().item(i).getNodeType() == Node.TEXT_NODE){
node.getChildNodes().item(i).setNodeValue(value);
return true;
}
}
return false;
}*/
/**
* Gets a node name without the namespace prefix.
*
* @param element the node.
* @return the name.
*/
public static String getNodeName(Element element){
String name = element.getNodeName();
String prefix = element.getPrefix();
if(prefix != null){
if(name.startsWith(prefix))
name = name.replace(prefix+":", "");
}
return name;
}
/**
* Gets a child element of a parent node with a given name.
*
* @param parent - the parent element
* @param name - the name of the child.
* @return - the child element.
*/
public static Element getNode(Element parent, String name){
if(parent == null)
return null;
for(int i=0; i<parent.getChildNodes().getLength(); i++){
if(parent.getChildNodes().item(i).getNodeType() != Node.ELEMENT_NODE){
continue;
}
Element child = (Element)parent.getChildNodes().item(i);
if(XmlUtil.getNodeName(child).equals(name)){
return child;
}
else if(name.contains("/")){
String parentName = name.substring(0,name.indexOf('/'));
if(XmlUtil.getNodeName(child).equals(parentName)){
child = getNode(child,name.substring(name.indexOf('/') + 1));
if(child != null){
return child;
}
}
}
child = getNode(child,name);
if(child != null){
return child;
}
}
return null;
}
/**
* Gets the text value of a node with a given name.
*
* @param parentNode the parent node of the node whose text value we are to get.
* this node is normally an xforms instance data node.
* @param name the name of the node.
* @return the node text value.
*/
public static String getNodeTextValue(Element parentNode,String name){
Element node = XmlUtil.getNode(parentNode,name);
if(node != null)
return XmlUtil.getTextValue(node);
return null;
}
/**
* Creates an xml document object from its text xml.
*
* @param xml the text xml.
* @return the document object.
*/
public static Document getDocument(String xml){
return XMLParser.parse(xml);
}
/**
* Converts an xml document to a string.
*
* @param doc the document.
* @return the xml string.
*/
public static String fromDoc2String(Document doc){
// String unformatted = flattenXML(doc.toString());
String pretty = prettifyXML(doc.toString());
return setDataNodeXMLNS(pretty);
}
private static String flattenXML(String s){
String flatS = s.replaceAll("> *<([^/])", "><$1")
.replaceAll("\n", "");
return flatS;
}
static native String prettifyXML(String xml)/*-{
var s = $wnd.beautifyXml(xml);
// var s = $wnd.formatXml(xml);
return s;
}-*/;
public static String escapeXMLAttribute(String s){
return s;
// if(s == null){ return null; }
// String ret = s.replace(">", ">");
// ret = ret.replace("<", "<");
// ret = ret.replace("'", "'");
// ret = ret.replace("\"", """);
// return ret;
}
/**
* So hacky I don't want to think about it.
*
* Takes in the xml text (as a string),
* looks for a specific phrase ("xmlnsCHANGEME") and modifies
* it such that it looks right when it comes time to displaying it
*
*
* @param namespaceURI
* @return
*/
public static String setDataNodeXMLNS(String xmlString){
return xmlString.replaceAll("xmlnsCHANGEME", "xmlns");
}
/**
* Gets the next sibling of a node whose type is Node.ELEMENT_NODE
*
* @param node the node whose next sibling element to get.
* @return the next sibling element.
*/
public static Element getNextElementSibling(Element node){
Node sibling = node.getNextSibling();
while(sibling != null){
if(sibling.getNodeType() == Node.ELEMENT_NODE)
return (Element)sibling;
sibling = sibling.getNextSibling();
}
return node;
}
public static Node getChildElement(Node node){
NodeList nodes = node.getChildNodes();
for(int index = 0; index < nodes.getLength(); index++){
Node child = nodes.item(index);
if(child.getNodeType() == Node.ELEMENT_NODE)
return child;
}
return node;
}
public static Node getChildCDATA(Node node){
NodeList nodes = node.getChildNodes();
for(int index = 0; index < nodes.getLength(); index++){
Node child = nodes.item(index);
if(child.getNodeType() == Node.CDATA_SECTION_NODE)
return child;
}
return node;
}
public static String getItextId(Element node) {
//Check if node has a ref attribute.
String ref = node.getAttribute("ref");
if(ref == null)
return null;
//Check if node has jr:itext value in the ref attribute value.
int pos = ref.indexOf("jr:itext('");
if(pos < 0)
return null;
//Get the itext id which starts at the 11th character.
return ref.substring(10,ref.lastIndexOf("'"));
}
}