source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSXSLT.java@ 25656

Last change on this file since 25656 was 25656, checked in by sjm84, 12 years ago

Some reformatting and reworking to help with the on-page xml viewing

  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/*
2 * GSXSLT.java
3 * Copyright (C) 2008 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19package org.greenstone.gsdl3.util;
20
21import java.io.BufferedWriter;
22import java.io.File;
23import java.io.FileWriter;
24import java.util.ArrayList;
25import java.util.Vector;
26
27import org.greenstone.util.GlobalProperties;
28import org.w3c.dom.Document;
29import org.w3c.dom.Element;
30import org.w3c.dom.NamedNodeMap;
31import org.w3c.dom.Node;
32import org.w3c.dom.NodeList;
33
34/** various functions for manipulating Greenstone xslt */
35public class GSXSLT
36{
37 public static void mergeStylesheets(Document main_xsl, Element extra_xsl, boolean overwrite)
38 {
39 mergeStylesheetsDebug(main_xsl, extra_xsl, overwrite, false, null, null);
40 }
41
42 /**
43 * takes a stylesheet Document, and adds in any child nodes from extra_xsl
44 * named templates overwrite any existing one, while match templates are
45 * just added to the end of teh stylesheet
46 */
47 public static void mergeStylesheetsDebug(Document main_xsl, Element extra_xsl, boolean overwrite, boolean debug, String firstDocFileName, String secondDocFileName)
48 {
49 if (debug)
50 {
51 System.err.println("ADDING DEBUG ELEMENTS WITH FILE NAME " + firstDocFileName);
52 insertDebugElements(main_xsl, firstDocFileName);
53 }
54
55 Element main = main_xsl.getDocumentElement();
56
57 NodeList children = GSXML.getChildrenByTagName(extra_xsl, "xsl:variable");
58 for (int i = 0; i < children.getLength(); i++)
59 {
60 Node node = children.item(i);
61 // If the new xsl:import element is identical (in terms of href attr value)
62 // to any in the merged document, don't copy it over
63 if (!isDuplicateElement(main, node, "xsl:variable", "name"))
64 {
65 main.appendChild(main_xsl.importNode(node, true));
66 }
67 }
68
69 children = extra_xsl.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "import");
70 for (int i = 0; i < children.getLength(); i++)
71 {
72 Node node = children.item(i);
73 // If the new xsl:import element is identical (in terms of href attr value)
74 // to any in the merged document, don't copy it over
75 if (!isDuplicateElement(main, node, "xsl:import", "href"))
76 {
77 // Import statements should be the first children of an xsl:stylesheet element
78 // If firstchild is null, then this xsl:import element will be inserted at the "end"
79 // Although Node.insertBefore() will first remove identical nodes before inserting, we check
80 // only the href attribute to see if they're "identical" to any pre-existing <xsl:import>
81 main.insertBefore(main_xsl.importNode(node, true), main.getFirstChild());
82 }
83 }
84
85 children = extra_xsl.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "include");
86 for (int i = 0; i < children.getLength(); i++)
87 {
88 Node node = children.item(i);
89 // If the new xsl:include element is identical (in terms of href attr value)
90 // to any in the merged document, don't copy it over
91 // Although Node.appendChild() will first remove identical nodes before appending, we check
92 // only the href attribute to see if they're "identical" to any pre-existing <xsl:include>
93 if (!isDuplicateElement(main, node, "xsl:include", "href"))
94 {
95 main.appendChild(main_xsl.importNode(node, true));
96 }
97 }
98
99 children = extra_xsl.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "output");
100 for (int i = 0; i < children.getLength(); i++)
101 {
102 Node node = children.item(i);
103 // If the new xsl:output element is identical (in terms of the value for the method attr)
104 // to any in the merged document, don't copy it over
105 if (!isDuplicateElement(main, node, "xsl:output", "method"))
106 {
107 main.appendChild(main_xsl.importNode(node, true));
108 }
109 }
110
111 children = extra_xsl.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "template");
112 for (int i = 0; i < children.getLength(); i++)
113 {
114 Node node = children.item(i);
115 // remove any previous occurrences of xsl:template with the same value for name
116 // or even the same value for match (should we use priorities for match?)
117
118 if (overwrite)
119 {
120 removeDuplicateElementsFrom(main, node, "xsl:template", "name");
121 removeDuplicateElementsFrom(main, node, "xsl:template", "match");
122 main.appendChild(main_xsl.importNode(node, true));
123 }
124 else if (!isDuplicateElement(main, node, "xsl:template", "name"))
125 {
126 main.appendChild(main_xsl.importNode(node, true));
127 }
128 }
129
130 if (debug)
131 {
132 System.err.println("ADDING DEBUG ELEMENTS WITH FILE NAME " + secondDocFileName);
133 insertDebugElements(main_xsl, secondDocFileName);
134 }
135 }
136
137 protected static void insertDebugElements(Document doc, String fileName)
138 {
139 NodeList htmlTags = GSXML.getHTMLStructureElements(doc);
140 System.err.println("HTML TAGS SIZE IS " + htmlTags.getLength());
141 for (int i = 0; i < htmlTags.getLength(); i++)
142 {
143 Element current = (Element) htmlTags.item(i);
144 if (current.getUserData("GSDEBUGFILENAME") == null)
145 {
146 Element xslParent = (Element) current.getParentNode();
147
148 while (xslParent.getNamespaceURI() != "http://www.w3.org/1999/XSL/Transform" && !xslParent.getNodeName().startsWith("xsl:"))
149 {
150 xslParent = (Element) xslParent.getParentNode();
151 }
152
153 System.err.println("ADDING FILE NAME " + fileName);
154 current.setUserData("GSDEBUGFILENAME", fileName, null);
155 current.setUserData("GSDEBUGXML", xslParent.cloneNode(true), null);
156 }
157 else
158 {
159 System.err.println("ALREADY SET!");
160 }
161 }
162 }
163
164 public static void inlineImportAndIncludeFiles(Document doc, String pathExtra, int depth)
165 {
166 inlineImportAndIncludeFilesDebug(doc, pathExtra, depth, false, null);
167 }
168
169 public static void inlineImportAndIncludeFilesDebug(Document doc, String pathExtra, int depth, boolean debug, String docFileName)
170 {
171 XMLConverter converter = new XMLConverter();
172
173 String path = pathExtra;
174 if (path == null)
175 {
176 path = "";
177 }
178
179 NodeList importList = doc.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "import");
180 NodeList includeList = doc.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "include");
181
182 if (importList.getLength() == 0)
183 {
184 importList = doc.getElementsByTagName("xsl:import");
185 }
186 if (includeList.getLength() == 0)
187 {
188 includeList = doc.getElementsByTagName("xsl:include");
189 }
190
191 for (int i = 0; i < importList.getLength() + includeList.getLength(); i++)
192 {
193 Element current = (Element) ((i < importList.getLength()) ? importList.item(i) : includeList.item(i - importList.getLength()));
194 String href = current.getAttribute("href");
195
196 String filePath = GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), "oran") + File.separator + "transform" + File.separator + path.replace("/", File.separator) + href.replace("/", File.separator);
197
198 try
199 {
200 Document inlineDoc = converter.getDOM(new File(filePath));
201
202 String newPath = path;
203 int lastSepIndex = href.lastIndexOf("/");
204 if (lastSepIndex != -1)
205 {
206 newPath += href.substring(0, lastSepIndex + 1);
207 }
208
209 //Do this recursively
210 inlineImportAndIncludeFilesDebug(inlineDoc, newPath, depth + 1, debug, filePath);
211 GSXSLT.mergeStylesheetsDebug(doc, inlineDoc.getDocumentElement(), false, debug, docFileName, filePath);
212 }
213 catch (Exception ex)
214 {
215 ex.printStackTrace();
216 return;
217 }
218 }
219
220 while (importList.getLength() > 0)
221 {
222 Element importElem = (Element) importList.item(0);
223 importElem.getParentNode().removeChild(importElem);
224 }
225 while (includeList.getLength() > 0)
226 {
227 Element includeElem = (Element) includeList.item(0);
228 includeElem.getParentNode().removeChild(includeElem);
229 }
230 }
231
232 public static void modifyConfigFormatForDebug(Document doc, String fileName)
233 {
234 NodeList templateNodes = doc.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "template");
235 if (templateNodes.getLength() == 0)
236 {
237 templateNodes = doc.getElementsByTagName("xsl:template");
238 }
239
240 String debugElementString = "";
241 debugElementString += "<span class=\"configDebugSpan\" style=\"display:none;\">";
242 debugElementString += " \"filename\":\"" + fileName + "\",";
243 debugElementString += " \"xml\":\"<xsl:value-of select=\"util:xmlNodeToString(.)\"/>\""; //<xsl:copy><xsl:copy-of select=\"@*\"/></xsl:copy>
244 debugElementString += "</span>";
245
246 XMLConverter converter = new XMLConverter();
247 Element debugElement = (Element) converter.getDOM("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xslt:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:xslt=\"output.xsl\" xmlns:gsf=\"http://www.greenstone.org/greenstone3/schema/ConfigFormat\">" + debugElementString + "</xslt:stylesheet>").getDocumentElement().getFirstChild();
248
249 for (int i = 0; i < templateNodes.getLength(); i++)
250 {
251 Element currentTemplate = (Element) templateNodes.item(i);
252 if (currentTemplate.getAttribute("match") != null && (currentTemplate.getAttribute("match").equals("gsf:metadata") || currentTemplate.getAttribute("match").equals("*") || currentTemplate.getAttribute("match").equals("format")))
253 {
254 continue;
255 }
256
257 if (currentTemplate.hasChildNodes())
258 {
259 currentTemplate.insertBefore(doc.importNode(debugElement.cloneNode(true), true), currentTemplate.getFirstChild());
260 }
261 else
262 {
263 currentTemplate.appendChild(doc.importNode(debugElement.cloneNode(true), true));
264 }
265 }
266 }
267
268 // In element main, tries to find any previous occurrence of elements with xsl-template-name=templateName,
269 // and whose named attribute (attributeName) has the same value as the same attribute in node.
270 // If this is the case, such a previous occurrence is removed from element main, since
271 // the new node will contain a more specific redefinition of this element.
272 public static void removeDuplicateElementsFrom(Element main, Node node, String templateName, String attrName)
273 {
274 String attr = ((Element) node).getAttribute(attrName);
275 if (!attr.equals(""))
276 {
277 Element old_template = GSXML.getNamedElement(main, templateName, attrName, attr);
278 if (old_template != null)
279 {
280 main.removeChild(old_template);
281 }
282 }
283 }
284
285 // Call this method on elements like xsl:include, xsl:import and xsl:output
286 // In element main, tries to find any previous occurrence of elements with xsl-element-name=xslName,
287 // and whose named attribute (attributeName) has the same value as the same attribute in node.
288 // If this is the case, it returns true, since the element would a complete duplicate for our intents.
289 public static boolean isDuplicateElement(Element main, Node node, String xslName, String attrName)
290 {
291 String attr = ((Element) node).getAttribute(attrName);
292 if (!attr.equals(""))
293 {
294 Element old_element = GSXML.getNamedElement(main, xslName, attrName, attr);
295 if (old_element != null)
296 {
297 return true;
298 }
299 }
300 return false;
301 }
302
303 /**
304 * takes any import or include nodes, and creates absolute path names for
305 * the files
306 */
307 public static void absoluteIncludePaths(Document stylesheet, String gsdl3_home, String site_name, String collection, String interface_name, ArrayList<String> base_interfaces)
308 {
309 Element base_node = stylesheet.getDocumentElement();
310 if (base_node == null)
311 {
312 return;
313 }
314 Node child = base_node.getFirstChild();
315 while (child != null)
316 {
317 String name = child.getNodeName();
318 if (name.equals("xsl:import") || name.equals("xsl:include"))
319 {
320 ((Element) child).setAttribute("href", GSFile.stylesheetFile(gsdl3_home, site_name, collection, interface_name, base_interfaces, ((Element) child).getAttribute("href")));
321 }
322 child = child.getNextSibling();
323 }
324 }
325
326 /**
327 * looks through a stylesheet for <xxx:template match='template_name'>
328 * inside this template it looks for any <xxx:value-of
329 * select='metadataList/metadata[@name=yyy]> elements, and extracts the
330 * metadata names into a Vector
331 */
332 public static Vector<String> extractWantedMetadata(Document stylesheet, String template_name)
333 {
334
335 Vector<String> metadata = new Vector<String>();
336 Element base_node = stylesheet.getDocumentElement();
337 NodeList templates = base_node.getElementsByTagNameNS("*", "template");
338 for (int i = 0; i < templates.getLength(); i++)
339 {
340 Element template = (Element) templates.item(i);
341 String match_name = template.getAttribute("match");
342 if (!match_name.equals(template_name))
343 {
344 continue; // we're only looking for specific templates
345 }
346 String mode = template.getAttribute("mode");
347 if (!mode.equals(""))
348 {
349 continue; // we only want ones without modes - these are processing ones, not display ones
350 }
351 // we have one that we want to look through
352 NodeList values = template.getElementsByTagNameNS("*", "value-of");
353 for (int v = 0; v < values.getLength(); v++)
354 {
355 String select = ((Element) values.item(v)).getAttribute("select");
356 if (select.startsWith("metadataList/metadata[@name="))
357 {
358 String[] bits = select.split("'|\"");
359 // there should be two quotes in teh string, therefore 3 items, and the second one is teh one we want
360 String name = bits[1];
361 metadata.add(name);
362 }
363 }
364 }
365 return metadata;
366 }
367
368}
Note: See TracBrowser for help on using the repository browser.