View Javadoc

1   /*
2    * Created on Sep 25, 2005. Copyright 1999-2006 Faculty of Mathematics, Physics
3    * and Informatics, Comenius University, Bratislava. This file is protected by
4    * the Mozilla Public License version 1.1 (the "License"); you may not use this
5    * file except in compliance with the License. You may obtain a copy of the
6    * License at http://euromath2.sourceforge.net/license.html Unless required by
7    * applicable law or agreed to in writing, software distributed under the
8    * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
9    * OF ANY KIND, either express or implied. See the License for the specific
10   * language governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.foRenderer;
13  import javax.xml.namespace.QName;
14  import javax.xml.transform.dom.DOMSource;
15  import org.w3c.dom.Attr;
16  import org.w3c.dom.Element;
17  import org.w3c.dom.NamedNodeMap;
18  import org.w3c.dom.Node;
19  import sk.baka.ikslibs.DOMUtils;
20  import sk.baka.ikslibs.Namespaces;
21  import sk.baka.ikslibs.ids.IDManager;
22  import sk.baka.ikslibs.modify.DOMChangeCollector;
23  import sk.baka.ikslibs.modify.IChangeCollector;
24  import sk.baka.ikslibs.splitted.SplittedDocHolder;
25  import sk.baka.xml.gene.CoordinatorInputKey;
26  import sk.baka.xml.gene.ExportUtils;
27  import sk.uniba.euromath.editor.IInputPreprocessor;
28  /***
29   * Preprocesses the FO renderer input.
30   * @author Martin Vysny
31   */
32  public class FOPreprocessor implements IInputPreprocessor {
33  	/***
34  	 * The renderer receives data using this pipe.
35  	 */
36  	private CoordinatorInputKey input;
37  	/*
38  	 * (non-Javadoc)
39  	 * @see sk.uniba.euromath.api.editor.IInputPreprocessor#init(sk.uniba.euromath.api.export.CoordinatorInputKey)
40  	 */
41  	public void init(CoordinatorInputKey input) {
42  		if (input == null)
43  			throw new IllegalArgumentException("input must not be null"); //$NON-NLS-1$
44  		if (this.input != null)
45  			throw new IllegalStateException("Already initialized."); //$NON-NLS-1$
46  		this.input = input;
47  	}
48  	/*
49  	 * (non-Javadoc)
50  	 * @see sk.uniba.euromath.api.editor.IInputPreprocessor#process(sk.uniba.euromath.api.export.changes.ChangeCollector)
51  	 */
52  	public DOMChangeCollector process(IChangeCollector source) {
53  		// process this node.
54  		// TODO MOTO> P3 remove cloning.
55  		final Node node = ((DOMChangeCollector) source).getSource().getNode()
56  				.cloneNode(true);
57  		// try {
58  		// ExportHelper.serializeDOM(new
59  		// FileOutputStream("/home/vyzivus/temp/preprocess-out.xml"),null,null,node);
60  		// }catch(IOException ex){
61  		// ex.printStackTrace();
62  		// }
63  		process(node);
64  		final DOMChangeCollector result = new DOMChangeCollector();
65  		result.init(new DOMSource(node, source.getSource().getSystemId()));
66  		// TODO MOTO> P2 update changes in result.
67  		return result;
68  	}
69  	/***
70  	 * <p>
71  	 * Processes given node and its children recursively. We have to:
72  	 * </p>
73  	 * <ul>
74  	 * <li>Change <code>emp:id</code> attributes to <code>id</code>
75  	 * attributes,</li>
76  	 * <li>Enclose text nodes in <code>fo:inline</code> with correct id, when
77  	 * processing source document.</li>
78  	 * </ul>
79  	 * @param node node to process.
80  	 */
81  	private void process(final Node node) {
82  		if (SplittedDocHolder.getGeneRef(node) != null) {
83  			// convert gene-ref processing instruction into
84  			// {ExportUtils.GENE_ID_ATTRIBUTE_QNAME.namespace}gene-ref element
85  			// containing attribute ID. This is because we cannot register
86  			// a handler in FOP that catches processing instructions.
87  			final Element generef = node.getOwnerDocument().createElementNS(
88  					ExportUtils.GENE_ID_ATTRIBUTE_QNAME.getNamespaceURI(),
89  					SplittedDocHolder.PI_GENEREF_TARGET);
90  			generef.setAttribute("id", SplittedDocHolder.getGeneRef(node)); //$NON-NLS-1$
91  			node.getParentNode().replaceChild(generef, node);
92  			return;
93  		}
94  		// process all children first.
95  		for (Node child = node.getFirstChild(); child != null;) {
96  			final Node nextSibling = child.getNextSibling();
97  			process(child);
98  			child = nextSibling;
99  		}
100 		// now, process the node itself.
101 		if (node.getNodeType() == Node.ELEMENT_NODE) {
102 			// replace gene:id attribute with id attribute
103 			final NamedNodeMap atts = node.getAttributes();
104 			if (atts != null) {
105 				final Attr emidAttr = (Attr) atts.getNamedItemNS(
106 						ExportUtils.GENE_ID_ATTRIBUTE_QNAME.getNamespaceURI(),
107 						ExportUtils.GENE_ID_ATTRIBUTE_QNAME.getLocalPart());
108 				if (emidAttr != null) {
109 					atts.removeNamedItemNS(ExportUtils.GENE_ID_ATTRIBUTE_QNAME
110 							.getNamespaceURI(),
111 							ExportUtils.GENE_ID_ATTRIBUTE_QNAME.getLocalPart());
112 					final Attr idAttr = node.getOwnerDocument()
113 							.createAttributeNS(null, "id"); //$NON-NLS-1$
114 					idAttr.setValue(emidAttr.getValue());
115 					atts.setNamedItemNS(idAttr);
116 					// TODO MOTO> P2 what if the element already contained an id
117 					// attribute?
118 				}
119 			}
120 		} else if (node.getNodeType() == Node.TEXT_NODE) {
121 			// wrap it in fo:inline element. but only if we are processing the
122 			// source document.
123 			if (input.info == null) {
124 				final Element inline = node.getOwnerDocument().createElementNS(
125 						Namespaces.XSL_FO_NAMESPACE, "fo:inline");//$NON-NLS-1$
126 				String id = IDManager.getIDNull(node,
127 						ExportUtils.GENE_ID_ATTRIBUTE_QNAME);
128 				assert id != null;
129 				// mark this id with ,N suffix so we'll know that we have
130 				// created this fo:inline element.
131 				id = id + ",N"; //$NON-NLS-1$
132 				final Attr idAttr = node.getOwnerDocument().createAttributeNS(
133 						null, "id");//$NON-NLS-1$
134 				idAttr.setNodeValue(id);
135 				inline.setAttributeNodeNS(idAttr);
136 				node.getParentNode().replaceChild(inline, node);
137 				inline.appendChild(node);
138 			}
139 		} else if (node.getNodeType() == Node.CDATA_SECTION_NODE) {
140 			throw new IllegalArgumentException("CDATA node occured");//$NON-NLS-1$
141 		} else if (node.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
142 			throw new IllegalArgumentException("EntityRef node occured");//$NON-NLS-1$
143 		}
144 	}
145 	/*
146 	 * (non-Javadoc)
147 	 * @see sk.uniba.euromath.api.editor.IInputPreprocessor#undo(sk.uniba.euromath.api.export.changes.ChangeCollector)
148 	 */
149 	public void undo(IChangeCollector source) {
150 		throw new AssertionError("Should not be called");//$NON-NLS-1$
151 	}
152 	/***
153 	 * Checks if given node is a generef element and if yes, returns value of
154 	 * its <code>id</code> attribute.
155 	 * @param node node to check.
156 	 * @return non-null value of id attribute if the element is gene-ref
157 	 * element, <code>null</code> otherwise.
158 	 */
159 	public static String getGenerefElementId(final Node node) {
160 		if (node.getNodeType() != Node.ELEMENT_NODE)
161 			return null;
162 		if (!DOMUtils.equalsNodeQName(node, GENEREF_MARK_ELEMENT))
163 			return null;
164 		return ((Element) node).getAttribute("id"); //$NON-NLS-1$
165 	}
166 	/***
167 	 * The mark element qname.
168 	 */
169 	public static QName GENEREF_MARK_ELEMENT = new QName(
170 			ExportUtils.GENE_ID_ATTRIBUTE_QNAME.getNamespaceURI(),
171 			SplittedDocHolder.PI_GENEREF_TARGET);
172 }