package marubinotto.util.xml; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; import marubinotto.util.Assert; import org.apache.commons.lang.UnhandledException; import org.jaxen.JaxenException; import org.jaxen.SimpleNamespaceContext; import org.jaxen.XPath; import org.jaxen.dom.DOMXPath; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * @version $Id: XmlTreeImpl.java 1286 2008-03-20 15:39:37Z morita $ */ public class XmlTreeImpl implements XmlTree { private static Map<String, XPath> xpathCache = new WeakHashMap<String, XPath>(); private Node root; private SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext(); private Map<String, String> xpaths = new HashMap<String, String>(); public XmlTreeImpl() { } public XmlTreeImpl(Node rootNode) throws Exception { setRoot(rootNode); } // XmlSerializable public void readFrom(InputStream xmlInput) throws Exception { Assert.Arg.notNull(xmlInput, "xmlInput"); setRoot(DomUtils.buildDocument(xmlInput)); } public void readFrom(File xmlFile) throws Exception { Assert.Arg.notNull(xmlFile, "xmlFile"); setRoot(DomUtils.buildDocument(xmlFile)); } public void fromXml(String xml) throws Exception { Assert.Arg.notNull(xml, "xml"); setRoot(DomUtils.buildDocument(xml)); } public void fromDom(Node node) throws Exception { setRoot(node); } public void writeTo(OutputStream xmlOut) throws Exception { Assert.Arg.notNull(xmlOut, "xmlOut"); DomUtils.serialize(getRoot(), xmlOut, null); } public void writeTo(OutputStream xmlOut, String encoding) throws Exception { Assert.Arg.notNull(xmlOut, "xmlOut"); DomUtils.serialize(getRoot(), xmlOut, encoding); } public void writeTo(File file) throws Exception { Assert.Arg.notNull(file, "file"); DomUtils.serialize(getRoot(), file, null); } public void writeTo(File file, String encoding) throws Exception { Assert.Arg.notNull(file, "file"); DomUtils.serialize(getRoot(), file, encoding); } public String toXml() { return DomUtils.toString(getRoot()); } public Node toDom() { return getRoot(); } // XmlTree public Node getRoot() { return root; } public void setRoot(Node rootNode) throws Exception { Assert.Arg.notNull(rootNode, "rootNode"); root = rootNode; initialize(); } public Document getOwnerDocument() { Node root = getRoot(); if (root == null) return null; if (root instanceof Document) { return (Document)root; } else { return root.getOwnerDocument(); } } public void setNamespacePrefix(String prefix, String namespaceUri) { Assert.Arg.notNull(prefix, "prefix"); Assert.Arg.notNull(namespaceUri, "namespaceUri"); namespaceContext.addNamespace(prefix, namespaceUri); } public Node selectSingleNode(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); return (Node)getXPath(xpath).selectSingleNode(getRoot()); } public Node selectSingleNode(String xpath, Locale locale) throws Exception { Assert.Arg.notNull(xpath, "xpath"); Assert.Arg.notNull(locale, "locale"); return DomUtils.selectByLang(selectNodes(xpath), locale); } @SuppressWarnings("unchecked") public List<Node> selectNodes(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); return getXPath(xpath).selectNodes(getRoot()); } public List<XmlTree> selectSubtrees(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); List<XmlTree> subtrees = new ArrayList<XmlTree>(); for (Iterator<Node> i = selectNodes(xpath).iterator(); i.hasNext();) { subtrees.add(createSubtree(i.next())); } return subtrees; } public List<String> selectValues(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); List<String> values = new ArrayList<String>(); for (Iterator<Node> i = selectNodes(xpath).iterator(); i.hasNext();) { values.add(DomUtils.getValue(i.next())); } return values; } public String stringValueOf(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); Node node = selectSingleNode(xpath); if (node == null) { return null; } return DomUtils.getValue(node); } public String stringValueOf(String xpath, Locale locale) throws Exception { Assert.Arg.notNull(xpath, "xpath"); Assert.Arg.notNull(locale, "locale"); Node node = selectSingleNode(xpath, locale); if (node == null) { return null; } return DomUtils.getValue(node); } public boolean booleanValueOf(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); return getXPath(xpath).booleanValueOf(getRoot()); } public Number numberValueOf(String xpath) throws Exception { Assert.Arg.notNull(xpath, "xpath"); return getXPath(xpath).numberValueOf(getRoot()); } // XPath mappings public void setXpaths(Map<String, String> xpaths) { Assert.Arg.notNull(xpaths, "xpaths"); this.xpaths.putAll(xpaths); } public Map<String, String> getXpaths() { return this.xpaths; } public String getXpath(String name) { Assert.Arg.notNull(name, "name"); String xpath = (String)getXpaths().get(name); if (xpath == null) { throw new IllegalArgumentException("Missing xpath mapping: " + name); } return xpath; } public String get(String name) { Assert.Arg.notNull(name, "name"); String xpath = getXpath(name); try { return stringValueOf(xpath); } catch (Exception e) { throw new UnhandledException(e); } } public String get(String name, Locale locale) { Assert.Arg.notNull(name, "name"); Assert.Arg.notNull(locale, "locale"); try { return stringValueOf(getXpath(name), locale); } catch (Exception e) { throw new UnhandledException(e); } } public boolean set(String name, String value) { return set(name, null, value); } public boolean set(String name, Locale locale, String value) { Assert.Arg.notNull(name, "name"); String xpath = getXpath(name); Node node = null; try { if (locale != null) { node = selectSingleNode(xpath, locale); } else { node = selectSingleNode(xpath); } } catch (Exception e) { throw new UnhandledException(e); } if (node == null) { return false; } DomUtils.setValue(node, value); return true; } // Protected Methods protected void initialize() throws Exception { setNamespacePrefix("xml", DomUtils.XML_NAMESPACE); setNamespacePrefix("xsi", DomUtils.XML_SCHEMA_NAMESPACE); } // Private methods private XPath getXPath(String xpath) throws JaxenException { XPath result = xpathCache.get(xpath); if (result == null) { result = new DOMXPath(xpath); result.setNamespaceContext(namespaceContext); xpathCache.put(xpath, result); } return result; } private XmlTreeImpl createSubtree(Node subtreeRoot) throws Exception { XmlTreeImpl tree = new XmlTreeImpl(subtreeRoot); tree.namespaceContext = namespaceContext; return tree; } }