blob: 5312e16e181e334ff8ba86eed516a78698671942 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.lenya.cms.editors.forms;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.environment.Request;
import org.apache.commons.lang.StringUtils;
import org.apache.excalibur.source.ModifiableSource;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;
import org.apache.lenya.cms.usecase.DocumentUsecase;
import org.apache.lenya.cms.usecase.UsecaseException;
import org.apache.lenya.cms.usecase.UsecaseMessage;
import org.apache.lenya.cms.usecase.xml.UsecaseErrorHandler;
import org.apache.lenya.cms.workflow.WorkflowUtil;
import org.apache.lenya.cms.workflow.usecases.UsecaseWorkflowHelper;
import org.apache.lenya.xml.DocumentHelper;
import org.apache.lenya.xml.ValidationUtil;
import org.apache.lenya.xml.XPath;
import org.apache.xindice.core.xupdate.XPathQueryFactoryImpl;
import org.apache.xindice.core.xupdate.XUpdateImpl;
import org.apache.xindice.xml.NamespaceMap;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xml.utils.PrefixResolverDefault;
import org.apache.xpath.XPathAPI;
import org.apache.xpath.objects.XObject;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmldb.common.xml.queries.XPathQueryFactory;
/**
* Multiple forms editor usecase.
*
* @version $Id$
*/
public class FormsEditor extends DocumentUsecase {
protected static final String VALIDATION_ERRORS = "private.validationErrors";
private static final class XUpdateAttributes {
/**
* <code>xupdateAttrExpr</code> The Xupdate expression
*/
public String xupdateAttrExpr = "";
/**
* <code>tagID</code> The tag ID
*/
public String tagID = "";
/**
* Set Xupdate attributes
* @param _xupdateAttrExpr The xupdate expression
* @param _tagID The tag id
*/
public XUpdateAttributes(String _xupdateAttrExpr, String _tagID) {
this.xupdateAttrExpr = _xupdateAttrExpr;
this.tagID = _tagID;
}
}
protected static final String WORKFLOW_INVOKED = "private.workflowInvoked";
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#getNodesToLock()
*/
protected org.apache.lenya.cms.repository.Node[] getNodesToLock() throws UsecaseException {
org.apache.lenya.cms.publication.Document doc = getSourceDocument();
Set nodes = new HashSet();
if (doc != null) {
nodes.add(doc.getRepositoryNode());
}
return (org.apache.lenya.cms.repository.Node[])
nodes.toArray(new org.apache.lenya.cms.repository.Node[nodes.size()]);
}
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#doCheckPreconditions()
*/
protected void doCheckPreconditions() throws Exception {
super.doCheckPreconditions();
if (!hasErrors()) {
org.apache.lenya.cms.publication.Document doc = getSourceDocument();
UsecaseWorkflowHelper.checkWorkflow(this.manager, this, getEvent(), doc, getLogger());
}
}
/**
* @see org.apache.lenya.cms.usecase.Usecase#advance()
*/
public void advance() throws UsecaseException {
super.advance();
String unnumberTagsXslUri = "fallback://lenya/modules/editors/usecases/forms/unnumberTags.xsl";
String numberTagsXslUri = "fallback://lenya/modules/editors/usecases/forms/numberTags.xsl";
Source unnumberTagsXslSource = null;
Source numberTagsXslSource = null;
SourceResolver resolver = null;
try {
resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
unnumberTagsXslSource = resolver.resolveURI(unnumberTagsXslUri);
numberTagsXslSource = resolver.resolveURI(numberTagsXslUri);
if (getParameterAsString("cancel") != null) {
getLogger().warn("Editing has been canceled");
// modifiableXmlSource.delete();
return;
}
Request request = ContextHelper.getRequest(this.context);
String encoding = request.getCharacterEncoding();
save(resolver, getSourceDocument(), unnumberTagsXslSource, numberTagsXslSource, encoding);
if (hasErrors()) {
setParameter(VALIDATION_ERRORS, getErrorMessages());
} else if (!getParameterAsBoolean(WORKFLOW_INVOKED, false)) {
deleteParameter(VALIDATION_ERRORS);
WorkflowUtil.invoke(this.manager,
getSession(),
getLogger(),
getSourceDocument(),
getEvent());
setParameter(WORKFLOW_INVOKED, Boolean.valueOf(true));
}
} catch (final Exception e) {
throw new UsecaseException(e);
} finally {
if (resolver != null) {
if (unnumberTagsXslSource != null) {
resolver.release(unnumberTagsXslSource);
}
if (numberTagsXslSource != null) {
resolver.release(numberTagsXslSource);
}
this.manager.release(resolver);
}
}
}
protected void doExecute() throws Exception {
super.doExecute();
advance();
List errors = (List) getParameter(VALIDATION_ERRORS);
if (errors != null) {
for (Iterator i = errors.iterator(); i.hasNext();) {
UsecaseMessage message = (UsecaseMessage) i.next();
addErrorMessage(message.getMessage(), message.getParameters());
}
}
}
/**
* Save the Form
* @param resolver
* @param lenyaDocument
* @param unnumberTagsXslSource
* @param numberTagsXslSource
* @throws ProcessingException
* @throws FactoryConfigurationError
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
* @throws XPathQueryConfigurationException
* @throws Exception
* @throws MalformedURLException
* @throws TransformerConfigurationException
* @throws TransformerException
*/
private void save(SourceResolver resolver, org.apache.lenya.cms.publication.Document lenyaDocument,
Source unnumberTagsXslSource, Source numberTagsXslSource,String encoding) throws Exception {
if (!lenyaDocument.exists()) {
throw new ProcessingException("The document [" + lenyaDocument + "] does not exist.");
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Save modifications to [" + lenyaDocument + "]");
}
Document doc = null;
DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
parserFactory.setValidating(false);
parserFactory.setNamespaceAware(true);
parserFactory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = parserFactory.newDocumentBuilder();
InputSource xmlInputSource = new InputSource(lenyaDocument.getInputStream());
Document document = builder.parse(xmlInputSource);
Document renumberedDocument = renumberDocument(document, unnumberTagsXslSource,numberTagsXslSource);
System.setProperty(XPathQueryFactory.class.getName(), XPathQueryFactoryImpl.class.getName());
XUpdateImpl xUpdate = new XUpdateImpl();
String editSelect = processElements(renumberedDocument, xUpdate);
setParameter("editSelect", editSelect);
Source validationSource = null;
Source unnumberTagsSource = null;
try {
String validationUri = lenyaDocument.getSourceURI() + ".validate";
validationSource = resolver.resolveURI(validationUri);
checkModifiability(validationSource);
String unnumberTagsUri = lenyaDocument.getSourceURI() + ".validate.unnumber";
unnumberTagsSource = resolver.resolveURI(unnumberTagsUri);
checkModifiability(unnumberTagsSource);
javax.xml.transform.Source transformXmlSource = new DOMSource(renumberedDocument);
javax.xml.transform.Source transformXslSource = new StreamSource(unnumberTagsXslSource.getInputStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
StreamResult unnumberXmlResult = new StreamResult(out);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(transformXslSource);
transformer.transform(transformXmlSource, unnumberXmlResult);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
doc = DocumentHelper.readDocument(in);
ValidationUtil.validate(this.manager, doc, getSourceDocument().getResourceType()
.getSchema(), new UsecaseErrorHandler(this));
} finally {
if (validationSource != null) {
resolver.release(validationSource);
}
if (unnumberTagsSource != null) {
resolver.release(unnumberTagsSource);
}
}
if (doc != null){
writeDocument(doc, getSourceDocument().getOutputStream(), encoding);
}
}
/**
* Process elements
* @param document
* @param xq
* @return A string.
* @throws Exception
*/
private String processElements(Document document, XUpdateImpl xq) throws Exception {
String editSelect = null;
String[] paramNames = getParameterNames();
for (int paramIndex = 0; paramIndex < paramNames.length; paramIndex++) {
String pname = paramNames[paramIndex];
getLogger().debug("Parameter: " + pname + " = " + getParameterAsString(pname));
// Extract the xpath to edit
if (pname.indexOf("edit[") >= 0) {
if (pname.endsWith("].x")) {
editSelect = pname.substring(5, pname.length() - 3);
getLogger().debug("Edit: " + editSelect);
}
deleteParameter(pname);
}
// Make sure we are dealing with an xupdate statement,
// else skip
if (pname.startsWith("<xupdate:")) {
String select = pname.substring(pname.indexOf("select") + 8);
select = select.substring(0, select.indexOf("\""));
getLogger().debug("Select Node: " + select);
// Check if node exists
PrefixResolver resolver = new FormPrefixResolver(document.getDocumentElement());
XObject xObject = XPathAPI.eval(document.getDocumentElement(), select, resolver);
NodeList nodes = xObject.nodelist();
if (nodes.getLength() == 0) {
getLogger().debug(".act(): Node does not exist (might have been deleted during update): "
+ select);
} else {
String xupdateModifications = null;
// now check for the different xupdate
// statements, and handle appropriately
if (pname.indexOf("xupdate:update-parent") > 0) {
getLogger().debug("UPDATE PARENT Node: " + pname);
// CDATA updates need to be handled
// seperately
if (pname.indexOf("<![CDATA[") > 0) {
xupdateModifications = updateCDATA(pname, true);
} else {
xupdateModifications = update(pname, select, nodes.item(0), true);
}
} else if (pname.indexOf("xupdate:update") > 0) {
getLogger().debug("UPDATE Node: " + pname);
// CDATA updates need to be handled
// seperately
if (pname.indexOf("<![CDATA[") > 0) {
xupdateModifications = updateCDATA(pname, false);
} else {
xupdateModifications = update(pname, select, nodes.item(0), false);
}
} else if (pname.indexOf("xupdate:append") > 0 && pname.endsWith(">.x")) {
xupdateModifications = append(pname.substring(0, pname.length() - 2));
// insert-before: in case of select/option
} else if (pname.indexOf("xupdate:insert-before") > 0 && pname.endsWith("/>")) {
if (!getParameterAsString(pname).equals("null")) {
xupdateModifications = insertBefore(getParameterAsString(pname));
editSelect = pname.substring(31,pname.length() - 3);
editSelect = changeTagNumber(editSelect, -1);
}
// insert-before: in case of image
} else if (pname.indexOf("xupdate:insert-before") > 0 && pname.endsWith(">.x")) {
xupdateModifications = insertBefore(pname.substring(0, pname.length() - 2));
// insert-after: in case of select/option
} else if (pname.indexOf("xupdate:insert-after") > 0 && pname.endsWith("/>")) {
if (!getParameterAsString(pname).equals("null")) {
xupdateModifications = insertAfter(getParameterAsString(pname));
editSelect = pname.substring(30,pname.length() - 3);
editSelect = changeTagNumber(editSelect, 1);
}
// insert-after: in case of image
} else if (pname.indexOf("xupdate:insert-after") > 0 && pname.endsWith(">.x")) {
xupdateModifications = insertAfter(pname.substring(0, pname.length() - 2));
} else if (pname.indexOf("xupdate:remove") > 0 && pname.endsWith("/>.x")) {
xupdateModifications = remove(pname.substring(0, pname.length() - 2));
editSelect = pname.substring(24,pname.length() - 3);
} else if (pname.endsWith(">.y")) {
getLogger().debug("Don't handle this: " + pname);
} else {
getLogger().debug("Don't handle this either: " + pname);
}
// Get hidden namespaces
String namespaces = getParameterAsString("namespaces");
// Add XML declaration
// NOTE: select/option is generating parameter
// which should be considered as null
if (xupdateModifications != null) {
xupdateModifications = "<?xml version=\"1.0\"?>" + xupdateModifications;
}
// now run the assembled xupdate query
if (xupdateModifications != null) {
getLogger().info("Execute XUpdate Modifications: " + xupdateModifications);
xq.setQString(xupdateModifications);
xq.setNamespaceMap(getNamespaceMap(namespaces));
xq.execute(document);
} else {
getLogger().debug("Parameter did not match any xupdate command: " + pname);
}
}
deleteParameter(pname);
}
}
return editSelect;
}
protected NamespaceMap getNamespaceMap(String namespaces) {
NamespaceMap nsMap = new NamespaceMap();
String[] namespace = namespaces.split("[\\s]+");
for (int i = 0; i < namespace.length; i++) {
String[] prefixAndUri = namespace[i].split("=");
String prefix = prefixAndUri[0];
String uri = prefixAndUri[1].replaceAll("\"", "");
int colonIndex = prefix.indexOf(":");
if (colonIndex == -1) {
nsMap.setDefaultNamespace(uri);
} else {
prefix = prefix.substring(colonIndex + 1);
if (!nsMap.containsKey(prefix)) {
nsMap.setNamespace(prefix, uri);
}
}
}
return nsMap;
}
/**
* Change the tag number of the selected node.
* The variable is used in a javascript in order to jump to the
* appropriate node after deleting or inserting a node.
* @param tagID The tagID where the new node is inserted.
* @param step int value for changing the tagID.
*/
protected String changeTagNumber(String tagID, int step){
String number = tagID.substring(tagID.lastIndexOf(".")+1,tagID.lastIndexOf("]")-1);
int num = Integer.parseInt(number) + step;
String newTagNumber = tagID.substring(0, tagID.lastIndexOf(".")+1);
return newTagNumber.concat(Integer.toString(num)+"']");
}
/**
* Writes a document to a modifiable source.
* @param document The document.
* @param oStream The source.
* @throws IOException if an error occurs.
* @throws TransformerConfigurationException if an error occurs.
* @throws TransformerException if an error occurs.
* @throws ProcessingException if an error occurs.
*/
protected void writeDocument(Document document, OutputStream oStream, String encoding) throws IOException,
TransformerConfigurationException, TransformerException, ProcessingException {
Writer writer = new OutputStreamWriter(oStream, encoding);
DocumentHelper.writeDocument(document, writer);
if (oStream != null) {
oStream.flush();
try {
oStream.close();
} catch (Throwable t) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Exception closing output stream: ", t);
}
throw new ProcessingException("Could not write document: ", t);
}
}
}
/**
* Checks if a source is modifiable.
* @param source The source.
* @throws ProcessingException if the source is not modifiable.
*/
protected void checkModifiability(Source source) throws ProcessingException {
if (!(source instanceof ModifiableSource)) {
throw new ProcessingException("Cannot write to source [" + source.getURI() + "]");
}
}
/**
* Get attributes from original node
* @param node Original node
* @return An XupdateAttributes class holding the attributes
*/
private XUpdateAttributes getAttributes(Node node) {
StringBuffer buf = new StringBuffer();
String xupdateString = "";
String tagID = "";
org.w3c.dom.NamedNodeMap attributes = node.getAttributes();
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
org.w3c.dom.Attr attribute = (org.w3c.dom.Attr) attributes.item(i);
getLogger().debug(".getAttributes(): " + attribute.getName() + " "
+ attribute.getValue());
if (!attribute.getName().equals("tagID")) {
String namespace = attribute.getNamespaceURI();
getLogger().debug(".getAttributes(): Namespace: " + namespace);
String namespaceAttribute = "";
if (namespace != null) {
namespaceAttribute = " namespace=\"" + namespace + "\"";
}
buf.append("<xupdate:attribute name=\"" + attribute.getName() + "\""
+ namespaceAttribute + ">" + attribute.getValue()
+ "</xupdate:attribute>");
} else {
buf.append("<xupdate:attribute name=\"tagID\">temp</xupdate:attribute>");
tagID = attribute.getValue();
}
}
xupdateString = buf.toString();
} else {
xupdateString = "";
}
getLogger().debug("Attributes: " + xupdateString);
return new XUpdateAttributes(xupdateString, tagID);
}
/**
* Get attributes from actual update
* @param update The actual update
* @param tagID The tag id to get the updates for
* @return An XupdateAttributes class holding the attributes
*/
private XUpdateAttributes getAttributes(String update, String tagID) {
getLogger().debug(update);
StringBuffer xupdateBuffer = new StringBuffer("<xupdate:attribute name=\"tagID\">temp</xupdate:attribute>");
String[] attributes = update.substring(0, update.indexOf(">")).split(" ");
for (int i = 1; i < attributes.length; i++) {
// TODO: beware of white spaces
int index = attributes[i].indexOf("=");
if (index > 0) {
String name = attributes[i].substring(0, index);
String value = attributes[i].substring(index + 2, attributes[i].length() - 1);
if (name.indexOf("xmlns") < 0) {
xupdateBuffer.append("<xupdate:attribute name=\"" + name + "\">");
xupdateBuffer.append(value).append("</xupdate:attribute>");
}
}
}
getLogger().debug("Attributes: " + xupdateBuffer.toString());
return new XUpdateAttributes(xupdateBuffer.toString(), tagID);
}
/**
* xupdate:update
* @param pname Name of the parent element
* @param select The attribute to update
* @param nodeToUpdate The node to update
* @param parent If true then parent element is part of update and attributes need to be updated
* resp. added or deleted
* @return the Xupdate statement
*/
private String update(String pname, String select, Node nodeToUpdate, boolean parent) {
getLogger().debug("Update node: " + select);
// deal with attribute values here..
if (nodeToUpdate.getNodeType() == Node.ATTRIBUTE_NODE) {
getLogger().debug("Update attribute: " + select);
String xupdateUpdate = pname + getParameterAsString(pname) + "</xupdate:update>";
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">"
+ xupdateUpdate + "</xupdate:modifications>";
/*
* And deal with mixed content here.. NOTE: Lexus has trouble with mixed content. As
* Workaround we insert-after the new node, remove the original node and replace the
* temporary tagID by the original tagID.
*/
}
getLogger().debug("Update element: " + select);
String namespace = nodeToUpdate.getNamespaceURI();
String namespaceAttribute = "";
if (namespace != null) {
namespaceAttribute = " namespace=\"" + namespace + "\"";
}
// NOTE: getAttributes adds the attribute tagID with value "temp",
// which will be replaced further down
XUpdateAttributes xa = getAttributes(nodeToUpdate);
String xupdateInsertAfter = null;
if (parent) {
xa = getAttributes(getParameterAsString(pname), xa.tagID);
xupdateInsertAfter = "<xupdate:insert-after select=\"" + select
+ " \"><xupdate:element name=\"" + new XPath(select).getNameWithoutPredicates()
+ "\"" + namespaceAttribute + ">" + xa.xupdateAttrExpr
+ removeParent(getParameterAsString(pname))
+ "</xupdate:element></xupdate:insert-after>";
} else {
xupdateInsertAfter = "<xupdate:insert-after select=\"" + select
+ " \"><xupdate:element name=\"" + new XPath(select).getNameWithoutPredicates()
+ "\"" + namespaceAttribute + ">" + xa.xupdateAttrExpr
+ getParameterAsString(pname) + "</xupdate:element></xupdate:insert-after>";
}
getLogger().debug(".update(): Update Node (insert-after): " + xupdateInsertAfter);
String xupdateRemove = "<xupdate:remove select=\"" + select + " \"/>";
getLogger().debug(".update(): Update Node (remove): " + xupdateRemove);
String xupdateUpdateAttribute = "<xupdate:update select=\""
+ new XPath(select).removePredicates(select) + "[@tagID='temp']/@tagID" + " \">"
+ xa.tagID + "</xupdate:update>";
getLogger().debug(".update(): Update Node (update tagID attribute): "
+ xupdateUpdateAttribute);
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">"
+ xupdateInsertAfter + xupdateRemove + xupdateUpdateAttribute
+ "</xupdate:modifications>";
}
/**
* xupdate:update CDATA
* @param pname The name of the parent element
* @param parent if true then attributes of parent will also be updated
* @return The Xupdate expression
*/
private String updateCDATA(String pname, boolean parent) {
String xupdateUpdate = pname + getParameterAsString(pname) + "]]></xupdate:update>";
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">"
+ xupdateUpdate + "</xupdate:modifications>";
}
/**
* xupdate:append
* @param pname The node to append to
* @return The Xupdate statement
*/
private String append(String pname) {
getLogger().debug(".append() APPEND Node: " + pname);
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
+ "</xupdate:modifications>";
}
/**
* xupdate:insert-before
* @param pname The node to insert before
* @return The Xupdate statement
*/
private String insertBefore(String pname) {
getLogger().debug(".insertBefore() INSERT-BEFORE Node: " + pname);
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
+ "</xupdate:modifications>";
}
/**
* xupdate:insert-after
* @param pname The node to insert after
* @return The Xupdate statement
*/
private String insertAfter(String pname) {
getLogger().debug(".insertAfter() INSERT-AFTER Node: " + pname);
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
+ "</xupdate:modifications>";
}
/**
* xupdate:remove
* @param pname The node to remove
* @return The Xupdate statement
*/
private String remove(String pname) {
getLogger().debug(".remove() REMOVE Node: " + pname);
return "<xupdate:modifications xmlns:xupdate=\"http://www.xmldb.org/xupdate\">" + pname
+ "</xupdate:modifications>";
}
/**
* Renumber the tags within a document. Each tag gets a unique number used in Xupdate
* expressions.
* @param doc The document to renumber
* @param unnumberTagsXSL The XSL stylesheet to remove the tagID attribute
* @param numberTagsXSL The XSL stylesheet to add the tagID attribute
* @return The renumbered document
* @throws UsecaseException
*/
private Document renumberDocument(Document doc, Source unnumberTagsXSL, Source numberTagsXSL)
throws UsecaseException {
try {
DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
parserFactory.setValidating(false);
parserFactory.setNamespaceAware(true);
parserFactory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = parserFactory.newDocumentBuilder();
TransformerFactory tf = TransformerFactory.newInstance();
// Remove tagIDs
Transformer ut = tf.newTransformer(new StreamSource(unnumberTagsXSL.getInputStream()));
Document unnumberedDocument = builder.newDocument();
ut.transform(new DOMSource(doc), new DOMResult(unnumberedDocument));
// Add tagIDs
Transformer nt = tf.newTransformer(new StreamSource(numberTagsXSL.getInputStream()));
Document renumberedDocument = builder.newDocument();
nt.transform(new DOMSource(unnumberedDocument), new DOMResult(renumberedDocument));
return renumberedDocument;
} catch (final Exception e) {
throw new UsecaseException(e);
}
}
/**
* Remove parent element
* @param xmlSnippet The XML snippet to remove the parent from
* @return The XML snippet with the parent removed
*/
private String removeParent(String xmlSnippet) {
String xmlSnippetWithoutParent = xmlSnippet;
xmlSnippetWithoutParent = xmlSnippetWithoutParent.substring(xmlSnippetWithoutParent.indexOf(">") + 1);
xmlSnippetWithoutParent = StringUtils.reverse(xmlSnippetWithoutParent);
xmlSnippetWithoutParent = xmlSnippetWithoutParent.substring(xmlSnippetWithoutParent.indexOf("<") + 1);
xmlSnippetWithoutParent = StringUtils.reverse(xmlSnippetWithoutParent);
return xmlSnippetWithoutParent;
}
/**
* Prefix resolver which uses the usecase parameters like
* "namespace.xhtml=http://www.w3.org/1999/xhtml" to resolve prefixes.
*/
public class FormPrefixResolver extends PrefixResolverDefault {
/**
* Ctor.
* @param context The context node.
*/
public FormPrefixResolver(Node context) {
super(context);
}
/**
* @see org.apache.xml.utils.PrefixResolver#getNamespaceForPrefix(java.lang.String,
* org.w3c.dom.Node)
*/
public String getNamespaceForPrefix(String prefix, Node context) {
String uri = super.getNamespaceForPrefix(prefix, context);
if (uri == null) {
uri = FormsEditor.this.getParameterAsString("namespace." + prefix);
}
return uri;
}
}
protected String getEvent() {
return "edit";
}
}