org.jopendocument.dom.OOXML Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008 jOpenDocument, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU
* General Public License Version 3 only ("GPL").
* You may not use this file except in compliance with the License.
* You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html
* See the License for the specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*
*/
/*
* Créé le 28 oct. 2004
*
*/
package org.jopendocument.dom;
import org.jopendocument.util.JDOMUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.XMLConstants;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.LazyMap;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.Parent;
import org.jdom.Text;
import org.jdom.xpath.XPath;
import org.xml.sax.SAXException;
/**
* Various bits of OpenDocument XML.
*
* @author Sylvain CUAZ
* @see #get(String)
*/
public class OOXML {
private static final Map instances = LazyMap.decorate(new HashMap(), new Transformer() {
public Object transform(Object input) {
return new OOXML((String) input);
}
});
/**
* Returns the instance that match the requested version.
*
* @param version either {@link OOUtils#OOo} or {@link OOUtils#OOo}.
* @return the corresponding instance.
*/
public static OOXML get(String version) {
return (OOXML) instances.get(version);
}
static public final String getTabS() {
return " ";
}
static public final String getLineBreakS() {
return " ";
}
static private final String rt2oo(String content, String tagName, String styleName) {
return content.replaceAll("\\[" + tagName + "\\]", "").replaceAll("\\[/" + tagName + "\\]", " ");
}
/**
* Encode spaces for OpenOffice, and escape characters for XML.
*
* @param s a string to encode, eg "hi\n 3<4".
* @return the string encoded in XML, eg "hi 3<4".
* @see #encodeWS(String)
*/
static public final String encodeOOWS(final String s) {
String tmp = JDOMUtils.OUTPUTTER.escapeElementEntities(s).replaceAll("\n", getLineBreakS()).replaceAll("\t", getTabS());
String res = "";
// les séries de plus d'un espace consécutifs
final Pattern p = Pattern.compile(" +");
final Matcher m = p.matcher(tmp);
int lastEnd = 0;
while (m.find()) {
// c == le nombre d'espaces
res += tmp.substring(lastEnd, m.start()) + " ";
lastEnd = m.end();
}
res += tmp.substring(lastEnd);
return res;
}
// *** instances
private final String version;
private OOXML(String version) {
this.version = version;
}
public final String getVersion() {
return this.version;
}
private NS getNS() {
return NS.get(getVersion());
}
/**
* Verify that the passed document is a valid OpenOffice.org 1 or ODF document.
*
* @param doc the xml to test.
* @return null if doc is valid, a String describing the pb
* otherwise.
*/
public final String isValid(Document doc) {
if (this.getVersion().equals(OOUtils.OD))
try {
return JDOMUtils.isValid(doc, XMLConstants.RELAXNG_NS_URI, getClass().getResource("oofficeDTDs/OpenDocument-strict-schema-v1.1.rng"));
} catch (SAXException e) {
throw new IllegalStateException("relaxNG schemas pb", e);
}
else {
// DTDs are stubborn, xmlns have to be exactly where they want
// in this case the root element
for (final Namespace n : getNS().getALL())
doc.getRootElement().addNamespaceDeclaration(n);
return JDOMUtils.isValidDTD(doc, OOUtils.getBuilderLoadDTD());
}
}
public final Element getLineBreak() {
return new Element("line-break", getNS().getTEXT());
}
public final Element getTab() {
return new Element("tab-stop", getNS().getTEXT());
}
protected final List encodeRT_L(String content, Map styles) {
String res = JDOMUtils.OUTPUTTER.escapeElementEntities(content);
final Iterator iter = styles.entrySet().iterator();
while (iter.hasNext()) {
final Entry e = (Entry) iter.next();
res = rt2oo(res, (String) e.getKey(), (String) e.getValue());
}
try {
return JDOMUtils.parseString(res, getNS().getALL());
} catch (JDOMException e) {
// should not happpen as we did escapeElementEntities which gives valid xml and then
// rt2oo which introduce only static xml
throw new IllegalStateException("could not parse " + res, e);
}
}
/**
* Convert rich text (with [] tags) into XML.
*
* @param content the string to convert, eg "texte [b]gras[/b]".
* @param styles the mapping from tagname (eg "b") to the name of the character style (eg
* "Gras").
* @return the corresponding element.
*/
public final Element encodeRT(String content, Map styles) {
return new Element("span", getNS().getTEXT()).addContent(encodeRT_L(content, styles));
}
// create the necessary
private Element createSpaces(String spacesS) {
return new Element("s", getNS().getTEXT()).setAttribute("c", spacesS.length() + "", getNS().getTEXT());
}
/**
* Encode a String to OO XML. Handles substition of whitespaces to their OO equivalent.
*
* @param s a plain ole String, eg "term\tdefinition".
* @return an Element suitable to be inserted in an OO XML document, eg
*
*
* <text:span>term<text:tab-stop/>definition</text:span>
* .
*/
public final Element encodeWS(final String s) {
return new Element("span", getNS().getTEXT()).setContent(encodeWSasList(s));
}
private final List encodeWSasList(final String s) {
final List res = new ArrayList();
final Matcher m = Pattern.compile("\n|\t| {2,}").matcher(s);
int last = 0;
while (m.find()) {
res.add(new Text(s.substring(last, m.start())));
switch (m.group().charAt(0)) {
case '\n':
res.add(getLineBreak());
break;
case '\t':
res.add(getTab());
break;
case ' ':
res.add(createSpaces(m.group()));
break;
default:
throw new IllegalStateException("unknown item: " + m.group());
}
last = m.end();
}
res.add(new Text(s.substring(last)));
return res;
}
@SuppressWarnings("unchecked")
public final void encodeWS(final Text t) {
final Parent parent = t.getParent();
final int ind = parent.indexOf(t);
t.detach();
parent.getContent().addAll(ind, encodeWSasList(t.getText()));
}
@SuppressWarnings("unchecked")
public final Element encodeWS(final Element elem) {
final XPath path;
try {
path = OOUtils.getXPath(".//text()", NS.getVersion(elem));
} catch (JDOMException e) {
// static path, hence always valid
throw new IllegalStateException("cannot create XPath", e);
}
try {
final Iterator iter = new ArrayList(path.selectNodes(elem)).iterator();
while (iter.hasNext()) {
final Text t = (Text) iter.next();
encodeWS(t);
}
} catch (JDOMException e) {
throw new IllegalArgumentException("cannot find text nodes of " + elem, e);
}
return elem;
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy