001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.util.jxpath;
018:
019: import org.apache.commons.jxpath.AbstractFactory;
020: import org.apache.commons.jxpath.JXPathContext;
021: import org.apache.commons.jxpath.Pointer;
022: import org.w3c.dom.Attr;
023: import org.w3c.dom.Document;
024: import org.w3c.dom.Element;
025: import org.w3c.dom.Node;
026:
027: /**
028: * A <a href="http://jakarta.apache.org/commons/jxpath">JXPath</a> <code>AbstractFactory</code>
029: * that creates DOM elements.
030: *
031: * @author <a href="http://www.apache.org/~sylvain/">Sylvain Wallez</a>
032: * @version $Id: DOMFactory.java 433543 2006-08-22 06:22:54Z crossley $
033: */
034:
035: public class DOMFactory extends AbstractFactory {
036:
037: /**
038: * Return <b>false</b> if this factory cannot create the requested object.
039: */
040: public boolean createObject(JXPathContext context, Pointer pointer,
041: Object parent, String name, int index) {
042: //FIXME: JXPath automatically creates attributes if the element already exists,
043: //but does not call this method if the element does not exit
044:
045: addDOMElement((Node) parent, index, name);
046:
047: return true;
048: }
049:
050: private void addDOMElement(Node parent, int index, String tag) {
051: int pos = tag.indexOf(':');
052: String prefix = null;
053: if (pos != -1) {
054: prefix = tag.substring(0, pos);
055: }
056: String uri = null;
057:
058: Node child = parent.getFirstChild();
059: int count = 0;
060: while (child != null) {
061: if (child.getNodeName().equals(tag)) {
062: count++;
063: }
064: child = child.getNextSibling();
065: }
066:
067: Document doc = parent.getOwnerDocument();
068:
069: if (doc != null) {
070: uri = getNamespaceURI((Element) parent, prefix);
071: } else {
072: if (parent instanceof Document) {
073: doc = (Document) parent;
074: if (prefix != null) {
075: throw new RuntimeException(
076: "Cannot map non-null prefix "
077: + "when creating a document element");
078: }
079: } else { // Shouldn't happen (must be a DocumentType object)
080: throw new RuntimeException("Node of class "
081: + parent.getClass().getName()
082: + " has null owner document "
083: + "but is not a Document");
084: }
085:
086: }
087:
088: // Keep inserting new elements until we have index + 1 of them
089: while (count <= index) {
090: Node newElement = doc.createElementNS(uri, tag);
091: parent.appendChild(newElement);
092: count++;
093: }
094: }
095:
096: public String getNamespaceURI(Element element, String prefix) {
097: Node tmp = element;
098: String nsAttr = prefix == null ? "xmlns" : "xmlns:" + prefix;
099:
100: while (tmp != null && tmp.getNodeType() == Node.ELEMENT_NODE) {
101: element = (Element) tmp;
102:
103: // First test element prefixes
104: if (prefix == null) {
105: if (element.getPrefix() == null) {
106: return element.getNamespaceURI();
107: }
108: } else if (prefix.equals(element.getPrefix())) {
109: return element.getNamespaceURI();
110: }
111:
112: // Note: stupid DOM api returns "" when an attribute doesn't exist, so we use the Attr node.
113: Attr nsAttrNode = ((Element) tmp).getAttributeNode(nsAttr);
114: if (nsAttrNode != null) {
115: return nsAttrNode.getValue();
116: }
117: tmp = tmp.getParentNode();
118: }
119: return null;
120: }
121:
122: public boolean declareVariable(JXPathContext context, String name) {
123: return false;
124: }
125: }
|