/* * Copyright (C) 2000 - 2011 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://www.openbluedragon.org/ * * $Id: $ */ package com.naryx.tagfusion.cfm.xml; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; import org.w3c.dom.Comment; import org.w3c.dom.DOMException; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.naryx.tagfusion.cfm.engine.catchDataFactory; import com.naryx.tagfusion.cfm.engine.cfData; import com.naryx.tagfusion.cfm.engine.cfStringData; import com.naryx.tagfusion.cfm.engine.cfStructData; import com.naryx.tagfusion.cfm.engine.cfmRunTimeException; public class XmlElementHashtable extends XmlNodeHashtable { protected XmlElementHashtable(Node n, boolean caseSensitive) { super(n, caseSensitive); } public boolean containsKey(Object key) { if (key.toString().equalsIgnoreCase("XmlNsPrefix")) return true; else if (key.toString().equalsIgnoreCase("XmlNsURI")) return true; else if (key.toString().equalsIgnoreCase("XmlText")) return true; else if (key.toString().equalsIgnoreCase("XmlCData")) return true; else if (key.toString().equalsIgnoreCase("XmlComment")) return true; else if (key.toString().equalsIgnoreCase("XmlAttributes")) return true; else if (key.toString().equalsIgnoreCase("XmlChildren")) return true; else if (key.toString().equalsIgnoreCase("XmlParent")) return true; else if (key.toString().equalsIgnoreCase("XmlNodes")) return true; else return super.containsKey(key); } public Object get(Object key) { if (key.toString().equalsIgnoreCase("XmlNsPrefix")) return getXmlNsPrefix(); else if (key.toString().equalsIgnoreCase("XmlNsURI")) return getXmlNsURI(); else if (key.toString().equalsIgnoreCase("XmlText")) return getXmlTextAndCData(); else if (key.toString().equalsIgnoreCase("XmlCData")) return getXmlTextAndCData(); else if (key.toString().equalsIgnoreCase("XmlComment")) return getXmlComment(); else if (key.toString().equalsIgnoreCase("XmlAttributes")) return getXmlAttributes(); else if (key.toString().equalsIgnoreCase("XmlChildren")) return getXmlChildren(); else if (key.toString().equalsIgnoreCase("XmlParent")) return getXmlParent(); else if (key.toString().equalsIgnoreCase("XmlNodes")) return getXmlNodes(); // Check for nodes of the same name NodeList nl = nodeData.getChildNodes(); Vector<cfXmlData> rtn = new Vector<cfXmlData>(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (equalKeys(node.getNodeName(), (String) key)) rtn.add(new cfXmlData(this, node, isCaseSensitive())); } if (rtn.size() == 1) { return rtn.get(0); } else if (rtn.size() > 1) { return new cfXmlDataArray(new cfXmlData(this, nodeData, isCaseSensitive()), rtn); } else { // Check for all other types of nodes Object o = super.get(key); if (o == null) { // Check if looking for an attribute o = ((cfXmlDataAttributeStruct) getXmlAttributes()).getData((String) key); } return o; } } public Object put(Object key, Object value) { try { if (key.toString().equalsIgnoreCase("XmlNsPrefix")) { String oldPrefix = null; try { oldPrefix = nodeData.getPrefix(); } catch (DOMException ex) { // Just log it com.nary.Debug.printStackTrace(ex); } nodeData.setPrefix(((cfData) value).toString()); return oldPrefix; } else if (key.toString().equalsIgnoreCase("XmlNsURI")) { // Do nothing return null; } else if (key.toString().equalsIgnoreCase("XmlText") || key.toString().equalsIgnoreCase("XmlCData")) { boolean isCDATA = key.toString().equalsIgnoreCase("XmlCData"); // Remove all text and CDATA nodes, and add 1 new one at the top remove("XmlText"); remove("XmlCData"); if (!((cfData) value).toString().trim().equals("")) { Node t = null; if (isCDATA) t = nodeData.getOwnerDocument().createCDATASection(((cfData) value).toString()); else t = nodeData.getOwnerDocument().createTextNode(((cfData) value).toString()); nodeData.insertBefore(t, nodeData.getFirstChild()); } nodeData.normalize(); return null; } else if (key.toString().equalsIgnoreCase("XmlComment")) { // Remove all comment nodes, and add 1 new one at the top remove(key); if (!((cfData) value).toString().trim().equals("")) { Comment c = nodeData.getOwnerDocument().createComment(((cfData) value).toString()); nodeData.insertBefore(c, nodeData.getFirstChild()); } nodeData.normalize(); return null; } else if (key.toString().equalsIgnoreCase("XmlAttributes")) { // Overwrite any existing xml attributes with these new ones if (value instanceof cfStructData) { cfXmlDataAttributeStruct attribs = (cfXmlDataAttributeStruct) getXmlAttributes(); cfStructData attribsToAdd = (cfStructData) value; Object[] keys = attribsToAdd.keys(); for (int i = 0; i < keys.length; i++) { String str = keys[i].toString(); cfData valueData = attribsToAdd.getData(str); attribs.setData(str, valueData); } } return null; } else if (key.toString().equalsIgnoreCase("XmlChildren")) { // Do nothing return null; } else if (key.toString().equalsIgnoreCase("XmlParent")) { // Do nothing return null; } else if (key.toString().equalsIgnoreCase("XmlNodes")) { // Do nothing return null; } else { if (value instanceof cfXmlData) { Node n = ((cfXmlData) value).getXMLNode(); if (n.getParentNode() != null) n = n.cloneNode(true); cfData d = (cfData) get(key); if (d != null) { if (d instanceof cfXmlData) return nodeData.replaceChild(n, ((cfXmlData) d).getXMLNode()); else if (d instanceof cfXmlDataArray) ((cfXmlDataArray) d).setData(1, new cfXmlData(n, ((cfXmlData) value).isCaseSensitive())); } else { nodeData.appendChild(n); } nodeData.normalize(); } else if (value instanceof cfStructData) { Element e = nodeData.getOwnerDocument().createElement((String) key); nodeData.appendChild(e); buildParentElement((cfStructData) value, e); nodeData.normalize(); } else if (value instanceof cfStringData) { if (((cfData) value).toString().trim().equals("")) { cfData d = (cfData) get(key); if (d != null) { if (d instanceof cfXmlData) nodeData.removeChild(((cfXmlData) d).getXMLNode()); else if (d instanceof cfXmlDataArray) ((cfXmlDataArray) d).removeAllElements(); nodeData.normalize(); } } } else { super.put(key, value); } return null; } } catch (cfmRunTimeException ex) { // Nothing else we can do here com.nary.Debug.printStackTrace(ex); } catch (DOMException ex) { // Nothing else we can do here com.nary.Debug.printStackTrace(ex); } return null; } protected void buildParentElement(cfStructData s, Node parent) throws cfmRunTimeException { try { Object[] keys = s.keys(); for (int i = 0; i < keys.length; i++) { String k = (String) keys[i]; cfData d = s.getData(k); if (d instanceof cfXmlData) { // Add as a child node parent.appendChild(((cfXmlData) d).getXMLNode()); } else if (d instanceof cfStructData) { // Create a child node and continue recursion Element e = parent.getOwnerDocument().createElement(k); parent.appendChild(e); buildParentElement((cfStructData) d, e); } } } catch (DOMException ex) { throw new cfmRunTimeException(catchDataFactory.javaMethodException("errorCode.javaException", ex.getClass().getName(), ex.getMessage(), ex)); } } public Object remove(Object key) { try { if (key.toString().equalsIgnoreCase("XmlNsPrefix")) { String oldPrefix = null; try { oldPrefix = nodeData.getPrefix(); } catch (DOMException ex) { // Just log it com.nary.Debug.printStackTrace(ex); } nodeData.setPrefix(null); return oldPrefix; } else if (key.toString().equalsIgnoreCase("XmlNsURI")) { return null; } else if (key.toString().equalsIgnoreCase("XmlText")) { // Remove all text nodes List<Node> ln = new ArrayList<Node>(); NodeList nl = nodeData.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() == Node.TEXT_NODE) ln.add(node); } Iterator<Node> itr = ln.iterator(); while (itr.hasNext()) nodeData.removeChild(itr.next()); nodeData.normalize(); return null; } else if (key.toString().equalsIgnoreCase("XmlCData")) { // Remove all cdata nodes List<Node> ln = new ArrayList<Node>(); NodeList nl = nodeData.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() == Node.CDATA_SECTION_NODE) ln.add(node); } Iterator<Node> itr = ln.iterator(); while (itr.hasNext()) nodeData.removeChild(itr.next()); nodeData.normalize(); return null; } else if (key.toString().equalsIgnoreCase("XmlComment")) { // Remove all comment nodes List<Node> ln = new ArrayList<Node>(); NodeList nl = nodeData.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() == Node.COMMENT_NODE) ln.add(node); } Iterator<Node> itr = ln.iterator(); while (itr.hasNext()) nodeData.removeChild((Node) itr.next()); nodeData.normalize(); return null; } else if (key.toString().equalsIgnoreCase("XmlAttributes")) { ((cfXmlDataAttributeStruct) getXmlAttributes()).clear(); return null; } else if (key.toString().equalsIgnoreCase("XmlChildren")) { ((cfXmlDataArray) getXmlChildren()).removeAllElements(); nodeData.normalize(); return null; } else if (key.toString().equalsIgnoreCase("XmlParent")) { return null; } else if (key.toString().equalsIgnoreCase("XmlNodes")) { ((cfXmlDataArray) getXmlNodes()).removeAllElements(); nodeData.normalize(); return null; } else { cfData d = (cfData) get(key); if (d != null) { if (d instanceof cfXmlData) nodeData.removeChild(((cfXmlData) d).getXMLNode()); else if (d instanceof cfXmlDataArray) ((cfXmlDataArray) d).removeAllElements(); nodeData.normalize(); } return null; } } catch (cfmRunTimeException ex) { // Nothing else we can do here com.nary.Debug.printStackTrace(ex); } catch (DOMException ex) { // Nothing else we can do here com.nary.Debug.printStackTrace(ex); } return null; } // default is a short dump public void dump(PrintWriter out, String _label, int _top) { cfData dd = null; out.write("<table class='cfdump_table_xml'>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlText"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlTextAndCData(); if (dd != null) dd.dump(out, "", _top); else out.write(""); out.write("</td></tr>"); dd = getXmlAttributes(); if ((dd != null) && (((cfXmlDataAttributeStruct) dd).keys().length > 0)) { out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlAttributes"); out.write("</td><td class='cfdump_td_value'>"); dd.dump(out, "", _top); out.write("</td></tr>"); } // dump children NodeList nl = nodeData.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { out.write("<tr><td class='cfdump_td_xml'>"); out.write(n.getNodeName()); out.write("</td><td class='cfdump_td_value'>"); dd = new cfXmlData(this, n, isCaseSensitive()); dd.dump(out, "", _top); out.write("</td></tr>"); } } out.write("</table>"); } public void dumpLong(PrintWriter out, String _label, int _top) { cfData dd = null; out.write("<table class='cfdump_table_xml'>"); out.write("<th class='cfdump_th_xml' colspan='2'>xml element</th>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlName"); out.write("</td><td class='cfdump_td_value'><b>"); dd = getXmlName(); if (dd != null) dd.dumpLong(out, "", _top); else out.write(""); out.write("</b></td></tr>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlNsPrefix"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlNsPrefix(); if (dd != null) dd.dumpLong(out, "", _top); else out.write(""); out.write("</td></tr>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlNsURI"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlNsURI(); if (dd != null) dd.dumpLong(out, "", _top); else out.write(""); out.write("</td></tr>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlText"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlTextAndCData(); if (dd != null) dd.dumpLong(out, "", _top); else out.write(""); out.write("</td></tr>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlComment"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlComment(); if (dd != null) dd.dumpLong(out, "", _top); else out.write(""); out.write("</td></tr>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlAttributes"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlAttributes(); if (dd != null) dd.dumpLong(out, "", _top); else out.write(""); out.write("</td></tr>"); out.write("<tr><td class='cfdump_td_xml'>"); out.write("XmlChildren"); out.write("</td><td class='cfdump_td_value'>"); dd = getXmlChildren(); if (dd != null) ((cfXmlDataArray) dd).dumpAsChildren(out); else out.write(""); out.write("</td></tr>"); out.write("</table>"); } protected cfData getXmlNsPrefix() { String oldPrefix = null; try { oldPrefix = nodeData.getPrefix(); } catch (DOMException ex) { // Just log it com.nary.Debug.printStackTrace(ex); } if (oldPrefix != null) return new cfStringData(oldPrefix.trim()); else return new cfStringData(""); } protected cfData getXmlNsURI() { if (nodeData.getNamespaceURI() != null) return new cfStringData(nodeData.getNamespaceURI().trim()); else return new cfStringData(""); } protected cfData getXmlTextAndCData() { boolean tfirst = true; NodeList nl = nodeData.getChildNodes(); StringBuilder texts = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); short nodeType = node.getNodeType(); if (nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE) { if (tfirst) texts = new StringBuilder(); else texts.append(System.getProperty("line.separator")); String nv = ""; try { nv = node.getNodeValue(); } catch (DOMException ex) { // Just log it com.nary.Debug.printStackTrace(ex); } texts.append(nv.trim()); tfirst = false; } } if (texts != null) return new cfStringData(texts.toString().trim()); else return new cfStringData(""); } protected cfData getXmlComment() { boolean cfirst = true; NodeList nl = nodeData.getChildNodes(); StringBuilder comments = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() == Node.COMMENT_NODE) { if (cfirst) comments = new StringBuilder(); else comments.append(System.getProperty("line.separator")); String nv = ""; try { nv = node.getNodeValue(); } catch (DOMException ex) { // Just log it com.nary.Debug.printStackTrace(ex); } comments.append(nv.trim()); cfirst = false; } } if (comments != null) return new cfStringData(comments.toString().trim()); else return new cfStringData(""); } protected cfData getXmlAttributes() { return new cfXmlDataAttributeStruct(new cfXmlData(this, nodeData, isCaseSensitive()), nodeData.getAttributes()); } protected cfData getXmlChildren() { NodeList nl = nodeData.getChildNodes(); Vector<cfXmlData> list = new Vector<cfXmlData>(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) list.add(new cfXmlData(this, node, isCaseSensitive())); } cfXmlDataArray rtn = new cfXmlDataArray(new cfXmlData(this, nodeData, isCaseSensitive()), list); rtn.setRequestedAsXmlChildren(true); return rtn; } protected cfData getXmlParent() { return new cfXmlData(this, nodeData.getParentNode(), isCaseSensitive()); } protected cfData getXmlNodes() { NodeList nl = nodeData.getChildNodes(); Vector<cfXmlData> list = new Vector<cfXmlData>(); for (int i = 0; i < nl.getLength(); i++) list.add(new cfXmlData(this, nl.item(i), isCaseSensitive())); return new cfXmlDataArray(new cfXmlData(this, nodeData, isCaseSensitive()), list); } }