1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.frontend.xeditor;
20
21 import java.io.IOException;
22 import java.util.HashMap;
23 import java.util.Map;
24
25 import javax.xml.parsers.DocumentBuilderFactory;
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.transform.TransformerException;
28
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.xpath.NodeSet;
31 import org.jaxen.BaseXPath;
32 import org.jaxen.JaxenException;
33 import org.jaxen.dom.DocumentNavigator;
34 import org.jaxen.expr.LocationPath;
35 import org.jaxen.expr.NameStep;
36 import org.jdom2.Document;
37 import org.jdom2.Element;
38 import org.jdom2.JDOMException;
39 import org.jdom2.Namespace;
40 import org.jdom2.Parent;
41 import org.mycore.common.MCRClassTools;
42 import org.mycore.common.MCRConstants;
43 import org.mycore.common.MCRException;
44 import org.mycore.common.content.MCRContent;
45 import org.mycore.common.content.MCRWrappedContent;
46 import org.mycore.common.content.transformer.MCRContentTransformer;
47 import org.mycore.common.content.transformer.MCRContentTransformerFactory;
48 import org.mycore.common.content.transformer.MCRParameterizedTransformer;
49 import org.mycore.common.content.transformer.MCRXSLTransformer;
50 import org.mycore.common.xml.MCRURIResolver;
51 import org.mycore.common.xml.MCRXPathEvaluator;
52 import org.mycore.common.xsl.MCRParameterCollector;
53 import org.mycore.frontend.xeditor.target.MCRInsertTarget;
54 import org.mycore.frontend.xeditor.target.MCRSubselectTarget;
55 import org.mycore.frontend.xeditor.target.MCRSwapTarget;
56 import org.mycore.frontend.xeditor.validation.MCRValidator;
57 import org.w3c.dom.Attr;
58 import org.w3c.dom.NamedNodeMap;
59 import org.w3c.dom.Node;
60 import org.xml.sax.SAXException;
61
62
63
64
65 public class MCRXEditorTransformer {
66
67 public int anchorID = 0;
68
69 private MCREditorSession editorSession;
70
71 private MCRBinding currentBinding;
72
73 private MCRParameterCollector transformationParameters;
74
75 private boolean withinSelectElement = false;
76
77 private boolean withinSelectMultiple = false;
78
79 public MCRXEditorTransformer(MCREditorSession editorSession, MCRParameterCollector transformationParameters) {
80 this.editorSession = editorSession;
81 this.transformationParameters = transformationParameters;
82 }
83
84 public MCRContent transform(MCRContent editorSource) throws IOException, JDOMException, SAXException {
85 editorSession.getValidator().clearRules();
86 editorSession.getSubmission().clear();
87
88 MCRContentTransformer transformer = MCRContentTransformerFactory.getTransformer("xeditor");
89 if (transformer instanceof MCRParameterizedTransformer) {
90 transformationParameters.setParameter("transformer", this);
91 MCRContent result = ((MCRParameterizedTransformer) transformer).transform(editorSource,
92 transformationParameters);
93 if (result instanceof MCRWrappedContent
94 && result.getClass().getName().contains(MCRXSLTransformer.class.getName())) {
95
96 result = ((MCRWrappedContent) result).getBaseContent();
97 }
98 editorSession.getValidator().clearValidationResults();
99 return result;
100 } else {
101 throw new MCRException("Xeditor needs parameterized MCRContentTransformer: " + transformer);
102 }
103 }
104
105 public void addNamespace(String prefix, String uri) {
106 MCRConstants.registerNamespace(Namespace.getNamespace(prefix, uri));
107 }
108
109 public void readSourceXML(String uri) throws JDOMException, IOException, SAXException, TransformerException {
110 editorSession.setEditedXML(uri);
111 }
112
113 public void setCancelURL(String cancelURL) {
114 editorSession.setCancelURL(cancelURL);
115 }
116
117 public void initializePostprocessor(Node postProcessorNode) {
118 NamedNodeMap attributes = postProcessorNode.getAttributes();
119 int attributesLength = attributes.getLength();
120 HashMap<String, String> attributeMap = new HashMap<>();
121 for (int i = 0; i < attributesLength; i++) {
122 Attr item = (Attr) attributes.item(i);
123 String attrName = item.getName();
124 String attrValue = item.getValue();
125 attributeMap.put(attrName, attrValue);
126 }
127
128 editorSession.getPostProcessor().setAttributes(attributeMap);
129 }
130
131 public void setPostProcessor(String clazz) {
132 try {
133 MCRXEditorPostProcessor instance = ((MCRXEditorPostProcessor) MCRClassTools.forName(clazz)
134 .getDeclaredConstructor()
135 .newInstance());
136 editorSession.setPostProcessor(instance);
137 } catch (ReflectiveOperationException e) {
138 throw new MCRException("Could not initialize Post-Processor with class" + clazz, e);
139 }
140 }
141
142 public String replaceParameters(String uri) {
143 return getXPathEvaluator().replaceXPaths(uri, false);
144 }
145
146 public void bind(String xPath, String initialValue, String name) throws JDOMException, JaxenException {
147 if (editorSession.getEditedXML() == null) {
148 createEmptyDocumentFromXPath(xPath);
149 }
150
151 if (currentBinding == null) {
152 currentBinding = editorSession.getRootBinding();
153 }
154
155 setCurrentBinding(new MCRBinding(xPath, initialValue, name, currentBinding));
156 }
157
158 private void setCurrentBinding(MCRBinding binding) {
159 this.currentBinding = binding;
160 editorSession.getValidator().setValidationMarker(currentBinding);
161 }
162
163 private void createEmptyDocumentFromXPath(String xPath) throws JaxenException, JDOMException {
164 Element root = createRootElement(xPath);
165 editorSession.setEditedXML(new Document(root));
166 editorSession.setBreakpoint("Starting with empty XML document");
167 }
168
169 private Element createRootElement(String xPath) throws JaxenException {
170 BaseXPath baseXPath = new BaseXPath(xPath, new DocumentNavigator());
171 LocationPath lp = (LocationPath) (baseXPath.getRootExpr());
172 NameStep nameStep = (NameStep) (lp.getSteps().get(0));
173 String prefix = nameStep.getPrefix();
174 Namespace ns = prefix.isEmpty() ? Namespace.NO_NAMESPACE : MCRConstants.getStandardNamespace(prefix);
175 return new Element(nameStep.getLocalName(), ns);
176 }
177
178 public void setValues(String value) {
179 currentBinding.setValues(value);
180 }
181
182 public void setDefault(String value) throws JaxenException, JDOMException {
183 currentBinding.setDefault(value);
184 editorSession.getSubmission().markDefaultValue(currentBinding.getAbsoluteXPath(), value);
185 }
186
187 public void unbind() {
188 setCurrentBinding(currentBinding.getParent());
189 }
190
191 public String getAbsoluteXPath() {
192 return currentBinding.getAbsoluteXPath();
193 }
194
195 public String getValue() {
196 return currentBinding.getValue();
197 }
198
199 public boolean hasValue(String value) {
200 editorSession.getSubmission().mark2checkResubmission(currentBinding);
201 return currentBinding.hasValue(value);
202 }
203
204 public void toggleWithinSelectElement(String attrMultiple) {
205 withinSelectElement = !withinSelectElement;
206 withinSelectMultiple = "multiple".equals(attrMultiple);
207 }
208
209 public boolean isWithinSelectElement() {
210 return withinSelectElement;
211 }
212
213 public boolean isWithinSelectMultiple() {
214 return withinSelectMultiple;
215 }
216
217 public String replaceXPaths(String text) {
218 return getXPathEvaluator().replaceXPaths(text, false);
219 }
220
221 public String replaceXPathOrI18n(String expression) {
222 return getXPathEvaluator().replaceXPathOrI18n(expression);
223 }
224
225 public String evaluateXPath(String xPathExpression) {
226 return getXPathEvaluator().evaluateXPath(xPathExpression);
227 }
228
229 public boolean test(String xPathExpression) {
230 return getXPathEvaluator().test(xPathExpression);
231 }
232
233 public MCRXPathEvaluator getXPathEvaluator() {
234 if (currentBinding != null) {
235 return currentBinding.getXPathEvaluator();
236 } else {
237 return new MCRXPathEvaluator(editorSession.getVariables(), (Parent) null);
238 }
239 }
240
241 public String repeat(String xPath, int minRepeats, int maxRepeats, String method)
242 throws JDOMException, JaxenException {
243 MCRRepeatBinding repeat = new MCRRepeatBinding(xPath, currentBinding, minRepeats, maxRepeats, method);
244 setCurrentBinding(repeat);
245 return StringUtils.repeat("a ", repeat.getBoundNodes().size());
246 }
247
248 private MCRRepeatBinding getCurrentRepeat() {
249 MCRBinding binding = currentBinding;
250 while (!(binding instanceof MCRRepeatBinding)) {
251 binding = binding.getParent();
252 }
253 return (MCRRepeatBinding) binding;
254 }
255
256 public int getNumRepeats() {
257 return getCurrentRepeat().getBoundNodes().size();
258 }
259
260 public int getMaxRepeats() {
261 return getCurrentRepeat().getMaxRepeats();
262 }
263
264 public int getRepeatPosition() {
265 return getCurrentRepeat().getRepeatPosition();
266 }
267
268 public void bindRepeatPosition() throws JDOMException, JaxenException {
269 setCurrentBinding(getCurrentRepeat().bindRepeatPosition());
270 editorSession.getValidator().setValidationMarker(currentBinding);
271 }
272
273 public String getSwapParameter(String action) throws JaxenException {
274 boolean direction = "down".equals(action) ? MCRSwapTarget.MOVE_DOWN : MCRSwapTarget.MOVE_UP;
275 return MCRSwapTarget.getSwapParameter(getCurrentRepeat(), direction);
276 }
277
278 public String getInsertParameter() throws JaxenException {
279 return MCRInsertTarget.getInsertParameter(getCurrentRepeat());
280 }
281
282 public int nextAnchorID() {
283 return ++anchorID;
284 }
285
286 public int getAnchorID() {
287 return anchorID;
288 }
289
290 public int previousAnchorID() {
291 return (anchorID == 0 ? 1 : anchorID - 1);
292 }
293
294 public void loadResource(String uri, String name) {
295 Element resource = MCRURIResolver.instance().resolve(uri);
296 editorSession.getVariables().put(name, resource);
297 }
298
299 public void addValidationRule(Node ruleElement) {
300 editorSession.getValidator().addRule(currentBinding.getAbsoluteXPath(), ruleElement);
301 }
302
303 public boolean hasValidationError() {
304 return editorSession.getValidator().hasError(currentBinding);
305 }
306
307 public Node getFailedValidationRule() {
308 return editorSession.getValidator().getFailedRule(currentBinding).getRuleElement();
309 }
310
311 public NodeSet getFailedValidationRules() {
312 NodeSet nodeSet = new NodeSet();
313 for (MCRValidator failedRule : editorSession.getValidator().getFailedRules()) {
314 nodeSet.addNode(failedRule.getRuleElement());
315 }
316 return nodeSet;
317 }
318
319 public String getSubselectParam(String href) {
320 return currentBinding.getAbsoluteXPath() + ":" + MCRSubselectTarget.encode(href);
321 }
322
323 public NodeSet getAdditionalParameters() throws ParserConfigurationException, TransformerException {
324 org.w3c.dom.Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
325 NodeSet nodeSet = new NodeSet();
326
327 Map<String, String[]> parameters = editorSession.getRequestParameters();
328 for (String name : parameters.keySet()) {
329 for (String value : parameters.get(name)) {
330 if ((value != null) && !value.isEmpty()) {
331 nodeSet.addNode(buildAdditionalParameterElement(dom, name, value));
332 }
333 }
334 }
335
336 String xPaths2CheckResubmission = editorSession.getSubmission().getXPaths2CheckResubmission();
337 if (!xPaths2CheckResubmission.isEmpty()) {
338 nodeSet.addNode(buildAdditionalParameterElement(dom, MCREditorSubmission.PREFIX_CHECK_RESUBMISSION,
339 xPaths2CheckResubmission));
340 }
341
342 Map<String, String> defaultValues = editorSession.getSubmission().getDefaultValues();
343 for (String xPath : defaultValues.keySet()) {
344 nodeSet.addNode(buildAdditionalParameterElement(dom, MCREditorSubmission.PREFIX_DEFAULT_VALUE + xPath,
345 defaultValues.get(xPath)));
346 }
347
348 editorSession.setBreakpoint("After transformation to HTML");
349 nodeSet.addNode(buildAdditionalParameterElement(dom, MCREditorSessionStore.XEDITOR_SESSION_PARAM,
350 editorSession.getCombinedSessionStepID()));
351
352 return nodeSet;
353 }
354
355 private org.w3c.dom.Element buildAdditionalParameterElement(org.w3c.dom.Document doc, String name, String value) {
356 org.w3c.dom.Element element = doc.createElement("param");
357 element.setAttribute("name", name);
358 element.setTextContent(value);
359 return element;
360 }
361
362 public void addCleanupRule(String xPath, String relevantIf) {
363 editorSession.getXMLCleaner().addRule(xPath, relevantIf);
364 }
365
366 public void declareParameter(String name, String defaultValue) {
367 Object currentValue = editorSession.getVariables().get(name);
368
369 if ((currentValue == null) || "".equals(currentValue)) {
370 editorSession.getVariables().put(name, defaultValue == null ? "" : defaultValue);
371 }
372 }
373 }