source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/XSLTUtil.java@ 36067

Last change on this file since 36067 was 36001, checked in by cstephen, 2 years ago

Surface cookie consent parameter as XML param.
Use commons StringUtils in XSLTUtil#getInterfaceStringsAsJavascript

  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1/*
2 * XSLTUtil.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 */
19
20/**
21 * Note (cstephen):
22 * Use of org.apache.commons.lang3.StringUtils can likely be removed when compiling
23 * for Java 1.13+, due to performance improvements in the standard library.
24 * https://stackoverflow.com/questions/16228992/commons-lang-stringutils-replace-performance-vs-string-replace
25 */
26
27package org.greenstone.gsdl3.util;
28
29import java.io.ByteArrayInputStream;
30import java.io.File;
31import java.io.UnsupportedEncodingException;
32import java.net.URLEncoder;
33import java.text.DateFormat;
34import java.text.SimpleDateFormat;
35import java.util.ArrayList;
36import java.util.Date;
37import java.util.Enumeration;
38import java.util.HashMap;
39import java.util.HashSet;
40import java.util.Locale;
41
42import javax.xml.parsers.DocumentBuilder;
43import javax.xml.parsers.DocumentBuilderFactory;
44
45import net.tanesha.recaptcha.ReCaptcha;
46import net.tanesha.recaptcha.ReCaptchaFactory;
47
48import org.apache.commons.lang3.StringUtils;
49import org.apache.log4j.Logger;
50import org.greenstone.util.GlobalProperties;
51import org.w3c.dom.Node;
52
53/**
54 * a class to contain various static methods that are used by the xslt
55 * stylesheets
56 */
57public class XSLTUtil
58{
59 protected static HashMap<String, ArrayList<String>> _foundTableValues = new HashMap<String, ArrayList<String>>();
60 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XSLTUtil.class.getName());
61 protected static HashMap<String, String> _stringVariables = new HashMap<String, String>();
62
63 public static void storeString(String name, String value)
64 {
65 _stringVariables.put(name, value);
66 }
67
68 public static String getString(String name)
69 {
70 return _stringVariables.get(name);
71 }
72
73 /* some tests */
74 public static boolean equals(String s1, String s2)
75 {
76 return s1.equals(s2);
77 }
78
79 public static boolean notEquals(String s1, String s2)
80 {
81 return !s1.equals(s2);
82 }
83
84 public static boolean exists(String s1, String s2)
85 {
86 return !s1.equals("");
87 }
88
89 public static boolean contains(String s1, String s2)
90 {
91 return (s1.indexOf(s2) != -1);
92 }
93
94 public static boolean startsWith(String s1, String s2)
95 {
96 return s1.startsWith(s2);
97 }
98
99 public static boolean endsWith(String s1, String s2)
100 {
101 return s1.endsWith(s2);
102 }
103
104 public static boolean lessThan(String s1, String s2)
105 {
106 return (s1.compareTo(s2) < 0);
107 }
108
109 public static boolean lessThanOrEquals(String s1, String s2)
110 {
111 return (s1.compareTo(s2) <= 0);
112 }
113
114 public static boolean greaterThan(String s1, String s2)
115 {
116 return (s1.compareTo(s2) > 0);
117 }
118
119 public static boolean greaterThanOrEquals(String s1, String s2)
120 {
121 return (s1.compareTo(s2) >= 0);
122 }
123
124 public static boolean csvContains(String user_groups, String this_group)
125 {
126 String[] groups_array = user_groups.split(",");
127 for (int i=0; i<groups_array.length; i++) {
128 if (groups_array[i].equals(this_group)) {
129 return true;
130 }
131 }
132 return false;
133
134 }
135 public static boolean oidIsMatchOrParent(String first, String second)
136 {
137 if (first.equals(second))
138 {
139 return true;
140 }
141
142 String[] firstParts = first.split(".");
143 String[] secondParts = second.split(".");
144
145 if (firstParts.length >= secondParts.length)
146 {
147 return false;
148 }
149
150 for (int i = 0; i < firstParts.length; i++)
151 {
152 if (!firstParts[i].equals(secondParts[i]))
153 {
154 return false;
155 }
156 }
157
158 return true;
159 }
160
161 public static String oidDocumentRoot(String oid)
162 {
163 String[] oidParts = oid.split("\\.");
164
165 return oidParts[0];
166 }
167
168 public static String replace(String orig, String match, String replacement)
169 {
170 return orig.replace(match, replacement);
171 }
172
173 public static String getNumberedItem(String list, int number)
174 {
175 String[] items = list.split(",", -1); //String[] items = StringUtils.split(list, ",", -1);
176 // Using StringUtils.split() causes an off-by-one error for the boolean operators (fqk)
177 // where boolean operators combining rows in multiforms are shifted up by 1 row.
178
179 if (items.length > number)
180 {
181 return items[number];
182 }
183 return ""; // index out of bounds
184 }
185
186 public static String getFormattedCCSSelection(String collections, String groups) {
187
188 String result = ",";
189 if (collections != null && !collections.equals("")) {
190 result += collections+",";
191 }
192 if (groups != null && !groups.equals("")) {
193 String[] gps = groups.split(",");
194 for (int i=0; i<gps.length; i++) {
195 result += "group."+gps[i].replace('/','.') +",";
196 }
197 }
198 return result;
199 }
200 /**
201 * Generates links to equivalent documents for a document with a default
202 * document icon/type. Links are generated from the parameters: a list of
203 * document icons which are each in turn embedded in the matching starting
204 * link tag in the list of docStartLinks (these starting links link to the
205 * equivalent documents in another format). Each link's start tag is closed
206 * with the corresponding closing tag in the docEndLinks list. Parameter
207 * token is the list separator. Parameter divider is the string that should
208 * separate each final link generated from the next. Returns a string that
209 * represents a sequence of links to equivalent documents, where the anchor
210 * is a document icon.
211 */
212 public static String getEquivDocLinks(String token, String docIconsString, String docStartLinksString, String docEndLinksString, String divider)
213 {
214 String[] docIcons = StringUtils.split(docIconsString, token, -1);
215 String[] startLinks = StringUtils.split(docStartLinksString, token, -1);
216 String[] endLinks = StringUtils.split(docEndLinksString, token, -1);
217
218 StringBuffer buffer = new StringBuffer();
219 for (int i = 0; i < docIcons.length; i++)
220 {
221 if (i > 0)
222 {
223 buffer.append(divider);
224 }
225 buffer.append(startLinks[i] + docIcons[i] + endLinks[i]);
226 }
227
228 return buffer.toString();
229 }
230
231 public static String getInterfaceText(String interface_name, String lang, String key)
232 {
233 return getInterfaceTextWithArgs(interface_name, lang, key, null);
234 }
235
236 public static String getInterfaceText(String interface_name, String lang, String key, String args_str)
237 {
238 String[] args = null;
239 if (args_str != null && !args_str.equals(""))
240 {
241 args = StringUtils.split(args_str, ";");
242 }
243 return getInterfaceTextWithArgs(interface_name, lang, key, args);
244 }
245
246 public static String getInterfaceText(String interface_name, String dictionary_name, String lang, String key, String args_str)
247 {
248 // now we allow looking for files in the interface's resources folder
249 CustomClassLoader my_loader = new CustomClassLoader(XSLTUtil.class.getClassLoader(), GSFile.interfaceResourceDir(GlobalProperties.getGSDL3Home(), interface_name));
250 String[] args = null;
251 if (args_str != null && !args_str.equals(""))
252 {
253 args = StringUtils.split(args_str, ";");
254 }
255
256 // try the specified dictionary first
257 Dictionary dict = new Dictionary(dictionary_name, lang, my_loader);
258 String result = dict.get(key, args);
259 if (result == null) {
260 // fall back to a general interface text search
261 return getInterfaceTextWithArgs(interface_name, lang, key, args);
262 }
263 result = result.replaceAll("__INTERFACE_NAME__", interface_name); // do we need to so this here?
264 return result;
265 }
266
267 public static String getInterfaceTextWithDOM(String interface_name, String lang, String key, Node arg_node)
268 {
269 return getInterfaceTextWithDOMMulti(interface_name, lang, key, arg_node);
270 }
271
272 public static String getInterfaceTextWithDOM(String interface_name, String lang, String key, Node arg1_node, Node arg2_node)
273 {
274 return getInterfaceTextWithDOMMulti(interface_name, lang, key, arg1_node, arg2_node);
275 }
276
277 public static String getInterfaceTextWithDOMMulti(String interface_name, String lang, String key, Node... nodes)
278 {
279 int num_nodes = nodes.length;
280 String[] args = null;
281 if (num_nodes != 0)
282 {
283 args = new String[num_nodes];
284
285 for (int i = 0; i < num_nodes; i++)
286 {
287 String node_str = XMLConverter.getString(nodes[i]);
288 args[i] = node_str;
289 }
290 }
291 return getInterfaceTextWithArgs(interface_name, lang, key, args);
292
293 }
294
295 /* This is the base method that actually does the work of looking up the various chain of dictionaries */
296 public static String getInterfaceTextWithArgs(String interface_name, String lang, String key, String[] args)
297 {
298 // now we allow looking for files in the interface's resources folder
299 CustomClassLoader my_loader = new CustomClassLoader(XSLTUtil.class.getClassLoader(), GSFile.interfaceResourceDir(GlobalProperties.getGSDL3Home(), interface_name));
300 Dictionary dict = new Dictionary("interface_" + interface_name, lang, my_loader);
301
302 String result = dict.get(key, args);
303 if (result == null)
304 {
305 //if not found, search a separate subdirectory named by the interface name. this is used for eg the flax interface. this could be replaced by new class loader option?
306 String sep_interface_dir = interface_name + File.separatorChar + lang + File.separatorChar + "interface";
307 dict = new Dictionary(sep_interface_dir, lang);
308 result = dict.get(key, args);
309 if (result != null)
310 {
311 return result;
312 }
313 }
314
315 if (result == null && !interface_name.startsWith("default")) {
316 // not found, try the default interface
317 if (interface_name.endsWith("2")) { // hack for interface_xxx2.properties
318 dict = new Dictionary("interface_default2", lang);
319 } else {
320 dict = new Dictionary("interface_default", lang);
321
322 }
323 result = dict.get(key, args);
324 }
325
326 if (result == null)
327 { // not found
328 return "?" + key + "?";
329 }
330 result = result.replaceAll("__INTERFACE_NAME__", interface_name);
331
332 return result;
333
334
335
336 }
337 public static String getInterfaceTextSubstituteArgs(String value, String args_str)
338 {
339 String[] args = null;
340 if (args_str != null && !args_str.equals("")) {
341 args = StringUtils.split(args_str, ";");
342 }
343
344 return Dictionary.processArgs(value,args);
345 }
346
347 public static Node getCollectionText(String collection, String site_name, String lang, String key)
348 {
349 return getCollectionTextWithArgs(collection, site_name, lang, key, null);
350 }
351
352 public static Node getCollectionText(String collection, String site_name, String lang, String key, String args_str)
353 {
354
355 String[] args = null;
356 if (args_str != null && !args_str.equals(""))
357 {
358 args = StringUtils.split(args_str, ";");
359 }
360
361 return getCollectionTextWithArgs(collection, site_name, lang, key, args);
362 }
363
364 // xslt didn't like calling the function with Node varargs, so have this hack for now
365 public static Node getCollectionTextWithDOM(String collection, String site_name, String lang, String key, Node n1)
366 {
367 return getCollectionTextWithDOMMulti(collection, site_name, lang, key, n1);
368 }
369
370 public static Node getCollectionTextWithDOM(String collection, String site_name, String lang, String key, Node n1, Node n2)
371 {
372 return getCollectionTextWithDOMMulti(collection, site_name, lang, key, n1, n2);
373 }
374
375 public static Node getCollectionTextWithDOM(String collection, String site_name, String lang, String key, Node n1, Node n2, Node n3)
376 {
377 return getCollectionTextWithDOMMulti(collection, site_name, lang, key, n1, n2, n3);
378 }
379
380 public static Node getCollectionTextWithDOM(String collection, String site_name, String lang, String key, Node n1, Node n2, Node n3, Node n4)
381 {
382 return getCollectionTextWithDOMMulti(collection, site_name, lang, key, n1, n2, n3, n4);
383 }
384
385 public static Node getCollectionTextWithDOMMulti(String collection, String site_name, String lang, String key, Node... nodes)
386 {
387 int num_nodes = nodes.length;
388 String[] args = null;
389 if (num_nodes != 0)
390 {
391 args = new String[num_nodes];
392
393 for (int i = 0; i < num_nodes; i++)
394 {
395 String node_str = XMLConverter.getString(nodes[i]);
396 args[i] = node_str;
397 }
398 }
399 return getCollectionTextWithArgs(collection, site_name, lang, key, args);
400 }
401
402 public static Node getCollectionTextWithArgs(String collection, String site_name, String lang, String key, String[] args)
403 {
404 try
405 {
406 DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
407
408 CustomClassLoader class_loader = new CustomClassLoader(XSLTUtil.class.getClassLoader(), GSFile.collectionResourceDir(GSFile.siteHome(GlobalProperties.getGSDL3Home(), site_name), collection));
409 Dictionary dict = new Dictionary("interface_custom", lang, class_loader);
410 String result = dict.get(key, args);
411 if (result != null)
412 {
413 return docBuilder.parse(new ByteArrayInputStream(("<fragment>" + result + "</fragment>").getBytes("UTF-8"))).getDocumentElement();
414 }
415 return docBuilder.parse(new ByteArrayInputStream(("<fragment>" + "text:" + collection + ":" + key + "</fragment>").getBytes())).getDocumentElement();
416 }
417 catch (Exception ex)
418 {
419 return null;
420 }
421 }
422
423 public static String getGenericText(String dictionary_name, String lang, String key) {
424 return getGenericTextWithArgs(dictionary_name, lang, key, null);
425 }
426
427 public String getGenericText(String dictionary_name, String lang, String key, String args_str) {
428 String[] args = null;
429 if (args_str != null && !args_str.equals("")) {
430 args = StringUtils.split(args_str, ";");
431 }
432 return getGenericTextWithArgs(dictionary_name, lang, key, args);
433 }
434
435 public static String getGenericTextWithArgs(String dictionary_name, String lang, String key, String[] args)
436 {
437 Dictionary dict = new Dictionary(dictionary_name, lang);
438 String result = dict.get(key, args);
439 if (result == null) {
440 return "_"+dictionary_name+"_"+key+"_";
441 }
442 return result;
443 }
444
445
446
447 public static boolean isImage(String mimetype)
448 {
449 if (mimetype.startsWith("image/"))
450 {
451 return true;
452 }
453 return false;
454 }
455
456 // formatting /preprocessing functions
457 // some require a language, so we'll have a language param for all
458 public static String toLower(String orig, String lang)
459 {
460 return orig.toLowerCase();
461 }
462
463 public static String toUpper(String orig, String lang)
464 {
465 return orig.toUpperCase();
466 }
467
468 public static String tidyWhitespace(String original, String lang)
469 {
470
471 if (original == null || original.equals(""))
472 {
473 return original;
474 }
475 String new_s = original.replaceAll("\\s+", " ");
476 return new_s;
477 }
478
479 public static String stripWhitespace(String original, String lang)
480 {
481
482 if (original == null || original.equals(""))
483 {
484 return original;
485 }
486 String new_s = original.replaceAll("\\s+", "");
487 return new_s;
488 }
489
490 public static byte[] toUTF8(String orig, String lang)
491 {
492 try
493 {
494 byte[] utf8 = orig.getBytes("UTF-8");
495 return utf8;
496 }
497 catch (Exception e)
498 {
499 logger.error("unsupported encoding");
500 return orig.getBytes();
501 }
502 }
503
504 public static String formatDate(String date, String lang)
505 {
506 String in_pattern = "yyyyMMdd";
507 String out_pattern = "dd MMMM yyyy";
508 if (date.length() == 6)
509 {
510 in_pattern = "yyyyMM";
511 out_pattern = "MMMM yyyy";
512 }
513 // remove the 00
514 else if (date.length() == 8 && date.endsWith("00")) {
515 date = date.substring(0,6);
516 in_pattern = "yyyyMM";
517 out_pattern = "MMMM yyyy";
518 }
519
520 SimpleDateFormat formatter = new SimpleDateFormat(in_pattern, new Locale(lang));
521 try
522 {
523 Date d = formatter.parse(date);
524 formatter.applyPattern(out_pattern);
525 String new_date = formatter.format(d);
526 return new_date;
527 }
528 catch (Exception e)
529 {
530 return date;
531 }
532
533 }
534
535 public static final int TS_SECS = 0;
536 public static final int TS_MILLISECS = 1;
537 public static final int F_DATE = 0;
538 public static final int F_TIME = 1;
539 public static final int F_DATETIME = 2;
540 public static final int F_DAYSAGO = 3;
541
542 public static String formatTimeStamp(String timestamp, int ts_type, int format_type, String lang) {
543 try {
544 long ts = Long.parseLong(timestamp);
545 if (ts_type == TS_SECS) {
546 ts = ts * 1000;
547 }
548 if (format_type == F_DAYSAGO) {
549 long current_time = new Date().getTime();
550 long days = (current_time - ts)/86400000;
551 return String.valueOf(days);
552 }
553 Date d = new Date(ts);
554 DateFormat df;
555 switch (format_type) {
556 case F_DATE:
557 df = DateFormat.getDateInstance(DateFormat.DEFAULT, new Locale(lang));
558 break;
559 case F_TIME:
560 df = DateFormat.getTimeInstance(DateFormat.DEFAULT, new Locale(lang));
561 break;
562 case F_DATETIME:
563 df = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, new Locale(lang));
564 break;
565 default:
566 df = DateFormat.getDateInstance(DateFormat.DEFAULT, new Locale(lang));
567 break;
568 }
569
570 return df.format(d);
571 } catch (Exception e) {
572
573 return timestamp + e.getMessage();
574 }
575
576 }
577 public static String getDetailFromDate(String date, String detail, String lang)
578 {
579 String in_pattern = "yyyyMMdd";
580 if (date.length() == 6)
581 {
582 in_pattern = "yyyyMM";
583 }
584 // remove the 00
585 else if (date.length() == 8 && date.endsWith("00")) {
586 date = date.substring(0,6);
587 in_pattern = "yyyyMM";
588 }
589
590 SimpleDateFormat formatter = new SimpleDateFormat(in_pattern, new Locale(lang));
591 try
592 {
593 Date d = formatter.parse(date);
594 if (detail.toLowerCase().equals("day"))
595 {
596 formatter.applyPattern("dd");
597 }
598 else if (detail.toLowerCase().equals("month"))
599 {
600 formatter.applyPattern("MMMM");
601 }
602 else if (detail.toLowerCase().equals("year"))
603 {
604 formatter.applyPattern("yyyy");
605 }
606 else
607 {
608 return "";
609 }
610 return formatter.format(d);
611 }
612 catch (Exception ex)
613 {
614 return "";
615 }
616 }
617
618 public static String formatLanguage(String display_lang, String lang)
619 {
620
621 return new Locale(display_lang).getDisplayLanguage(new Locale(lang));
622 }
623
624 public static boolean checkFileExistence(String site_name, String filePath){
625
626 String gsdl3_home = GlobalProperties.getGSDL3Home();
627 //Remove leading file separator
628 filePath = filePath.replaceAll("^/+", "");
629 //Remove duplicates and replace by separator for current platform
630 filePath = filePath.replaceAll("/+", File.separator);
631 //Create full path to check
632 String fullPath = GSFile.siteHome(gsdl3_home, site_name) + File.separator + filePath;
633 File file = new File(fullPath);
634 if (file.exists() && file.isFile()) {
635 return true;
636 }
637 return false;
638 }
639
640 public static String uriEncode(String input)
641 {
642 String result = "";
643 try {
644 result = URLEncoder.encode(input, "UTF-8");
645 } catch (UnsupportedEncodingException e) {
646 e.printStackTrace();
647 }
648
649 return result;
650
651 }
652
653 public static String cgiSafe(String original, String lang)
654 {
655
656 original = original.replace('&', ' ');
657 original = original.replaceAll(" ", "%20");
658 return original;
659 }
660
661 public static String formatBigNumber(String num, String lang)
662 {
663
664 String num_str = num;
665 char[] num_chars = num_str.toCharArray();
666 String zero_str = "";
667 String formatted_str = "";
668
669 for (int i = num_chars.length - 4; i >= 0; i--)
670 {
671 zero_str += '0';
672 }
673
674 String sig_str = "";
675 for (int i = 0; i < 3 && i < num_chars.length; i++)
676 {
677 sig_str = sig_str + num_chars[i];
678 if (i == 1 && i + 1 < num_chars.length)
679 {
680 sig_str = sig_str + ".";
681 }
682 }
683
684 int sig_int = Math.round(Float.parseFloat(sig_str));
685 String new_sig_str = sig_int + "";
686 if (sig_str.length() > 2)
687 {
688 new_sig_str = sig_int + "0";
689 }
690
691 char[] final_chars = (new_sig_str + zero_str).toCharArray();
692 int count = 1;
693 for (int i = final_chars.length - 1; i >= 0; i--)
694 {
695 formatted_str = final_chars[i] + formatted_str;
696 if (count == 3 && i != 0)
697 {
698 formatted_str = "," + formatted_str;
699 count = 1;
700 }
701 else
702 {
703 count++;
704 }
705 }
706 return formatted_str;
707 }
708
709 public static String hashToSectionId(String hashString)
710 {
711 if (hashString == null || hashString.length() == 0)
712 {
713 return "";
714 }
715
716 int firstDotIndex = hashString.indexOf(".");
717 if (firstDotIndex == -1)
718 {
719 return "";
720 }
721
722 String sectionString = hashString.substring(firstDotIndex + 1);
723
724 return sectionString;
725 }
726
727 public static String hashToDepthClass(String hashString)
728 {
729 if (hashString == null || hashString.length() == 0)
730 {
731 return "";
732 }
733
734 String sectionString = hashToSectionId(hashString);
735
736 int count = sectionString.split("\\.").length;
737
738 if (sectionString.equals(""))
739 {
740 return "sectionHeaderDepthTitle";
741 }
742 else
743 {
744 return "sectionHeaderDepth" + count;
745 }
746 }
747
748 public static String escapeNewLines(String str)
749 {
750 if (str == null || str.length() < 1)
751 {
752 return null;
753 }
754 return str.replace("\n", "\\\n");
755 }
756
757 public static String escapeQuotes(String str)
758 {
759 if (str == null || str.length() < 1)
760 {
761 return null;
762 }
763 return str.replace("\"", "\\\"");
764 }
765 public static String escapeAngleBrackets(String str)
766 {
767 if (str == null || str.length() < 1)
768 {
769 return null;
770 }
771 return str.replace("<", "&lt;").replace(">", "&gt;");
772 }
773
774 public static String escapeNewLinesAndQuotes(String str)
775 {
776 if (str == null || str.length() < 1)
777 {
778 return null;
779 }
780 return escapeNewLines(escapeQuotes(str));
781 }
782
783 public static String escapeNewLinesQuotesAngleBracketsForJSString(String str)
784 {
785 // The \n and " becomes \\\n and \\\"
786 // but the <> are escaped/encoded for html, i.e. &gt; and &lt;
787 if (str == null || str.length() < 1)
788 {
789 return null;
790 }
791 return escapeAngleBrackets(escapeNewLines(escapeQuotes(str)));
792 }
793 public static String getGlobalProperty(String name)
794 {
795 return GlobalProperties.getProperty(name);
796 }
797
798 public static void clearMetadataStorage()
799 {
800 _foundTableValues.clear();
801 }
802
803 public static boolean checkMetadataNotDuplicate(String name, String value)
804 {
805 if (_foundTableValues.containsKey(name))
806 {
807 for (String mapValue : _foundTableValues.get(name))
808 {
809 if (mapValue.equals(value))
810 {
811 return false;
812 }
813 }
814 _foundTableValues.get(name).add(value);
815 return true;
816 }
817
818 ArrayList<String> newList = new ArrayList<String>();
819 newList.add(value);
820
821 _foundTableValues.put(name, newList);
822
823 return true;
824 }
825
826 public static String reCAPTCHAimage(String publicKey, String privateKey)
827 {
828 ReCaptcha c = ReCaptchaFactory.newReCaptcha(publicKey, privateKey, false);
829 return c.createRecaptchaHtml(null, null);
830 }
831
832 /**
833 * Generates a Javascript object graph to store language strings. Leaf nodes are the key, and their value the string.
834 * Further preceding nodes denote the prefix of the string within the language strings property file.
835 * Accessing a language string from the object graph can be done as such: 'const myString = gs.text.{prefix}.{key};'
836 * @param interfaceName The name of the interface to retrieve language strings for.
837 * @param lang The language to retrieve.
838 * @param prefix The prefix to to retrieve strings under. E.g. a value of 'atea.macroniser' will only retrieve strings prefixed with that value.
839 * @return Stringified Javascript code that will generate the language string object graph.
840 */
841 public static String getInterfaceStringsAsJavascript(String interfaceName, String lang, String prefix)
842 {
843 String prependToPrefix = "gs.text";
844 return XSLTUtil.getInterfaceStringsAsJavascript(interfaceName, lang, prefix, prependToPrefix);
845 }
846
847 /**
848 * Generates a Javascript object graph to store language strings. Leaf nodes are the key, and their value the string.
849 * Further preceding nodes denote the prefix of the string within the language strings property file.
850 * Accessing a language string from the object graph can be done as such: 'const myString = {prependToPrefix}.{prefix}.{key};'
851 * @param interfaceName The name of the interface to retrieve language strings for.
852 * @param lang The language to retrieve.
853 * @param prefix The prefix to to retrieve strings under. E.g. a value of 'atea.macroniser' will only retrieve strings prefixed with that value.
854 * @param prependToPrefix An accessor string to prepend to the generated JS object graph.
855 * @return Stringified Javascript code that will generate the language string object graph.
856 */
857 public static String getInterfaceStringsAsJavascript(String interfaceName, String lang, String prefix, String prependToPrefix)
858 {
859 // now we allow looking for files in the interface's resources folder
860 CustomClassLoader my_loader = new CustomClassLoader(
861 XSLTUtil.class.getClassLoader(),
862 GSFile.interfaceResourceDir(GlobalProperties.getGSDL3Home(), interfaceName)
863 );
864
865 StringBuffer outputStr = new StringBuffer();
866 HashSet<String> initialisedNodes = new HashSet<>();
867
868 // The dictionaries to pull keys from
869 String[] dictionaries = new String[] {
870 "interface_" + interfaceName,
871 "interface_default",
872 "interface_default2"
873 };
874
875 for (String dictName : dictionaries)
876 {
877 // get all the *keys* from the english dictionary as this is a complete set
878 Dictionary dict = new Dictionary(dictName, "en", my_loader);
879 Enumeration<String> keys = dict.getKeys();
880 if (keys == null) {
881 continue;
882 }
883
884 // Get all properties in the language-specific dictionary with the given key prefix
885 // Create Javascript strings of the form:
886 // prependToPrefix.key="value";\n
887 while (keys.hasMoreElements())
888 {
889 String key = keys.nextElement();
890 if (key.startsWith(prefix))
891 {
892 int lastDotIndex = StringUtils.lastIndexOf(key, '.');
893 // If this is true, the key is nested under nodes that we might have to construct
894 if (lastDotIndex > 0) {
895 // Builds the JS object structure we need to access the key.
896 // Also has the side effect of ensuring that any '.' characters in
897 // the key are valid once parsed by the JS engine.
898 buildJSObjectGraph(
899 outputStr,
900 prependToPrefix + "." + StringUtils.substring(key, 0, lastDotIndex), // Strip the actual key from the path
901 initialisedNodes
902 );
903 }
904
905 // get the language dependent value for the key. This will return the english if no value found for the given lang
906 String value = getInterfaceText(interfaceName, dictName, lang, key, null);
907 outputStr.append(prependToPrefix + "." + key + "=\"" + value + "\";\n");
908 }
909 }
910 }
911
912 return outputStr.toString();
913 }
914
915 /**
916 * Builds a string that will initialize an empty javascript object.
917 * I.e. 'gs.text??={};'.
918 * @param buffer The buffer to append the string to.
919 * @param objectPath The path to the JS object to initialize. E.g. gs.text.atea.
920 * @param isRootObject A value indicating whether the object is a root object. If not, a logical nullish assignment statement will be built in order to produce cleaner javascript.
921 */
922 private static void buildJSObjectInitializer(
923 StringBuffer buffer,
924 String objectPath,
925 Boolean isRootObject
926 )
927 {
928 if (!isRootObject) {
929 buffer.append(objectPath + "??={};\n");
930 return;
931 }
932
933 buffer.append("if(typeof " + objectPath + "===\"undefined\"){" + objectPath + "={};}\n");
934 }
935
936 /**
937 * Builds a string that will initialize a javascript object graph.
938 * I.e. the structure required to access the final property on the object graph 'gs.text.atea.asr'.
939 * @param buffer The buffer to append the string to.
940 * @param objectGraph The object graph to build.
941 * @param visitedNodes A map of previously built nodes. Updated to add nodes that are produced in this function.
942 */
943 private static void buildJSObjectGraph(
944 StringBuffer buffer,
945 String objectGraph,
946 HashSet<String> preBuiltNodes
947 )
948 {
949 if (objectGraph == null) {
950 return;
951 }
952
953 String[] nodes = StringUtils.split(objectGraph, '.');
954
955 if (!preBuiltNodes.contains(nodes[0])) {
956 buildJSObjectInitializer(buffer, nodes[0], true);
957 preBuiltNodes.add(nodes[0]);
958 }
959
960 if (nodes.length == 1) {
961 return;
962 }
963
964 String currentDepth = nodes[0];
965 for (int i = 1; i < nodes.length; i++) {
966 currentDepth += "." + nodes[i];
967 if (preBuiltNodes.contains(currentDepth)) {
968 continue;
969 }
970
971 buildJSObjectInitializer(buffer, currentDepth, false);
972 preBuiltNodes.add(currentDepth);
973 }
974 }
975
976 public static String xmlNodeToString(Node node)
977 {
978 return GSXML.xmlNodeToString(node);
979 }
980
981 // Test from cmdline with:
982 // java -classpath /research/ak19/gs3-svn/web/WEB-INF/lib/gsdl3.jar:/research/ak19/gs3-svn/web/WEB-INF/lib/log4j-1.2.8.jar:/research/ak19/gs3-svn/web/WEB-INF/classes/ org.greenstone.gsdl3.util.XSLTUtil
983 public static void main(String args[])
984 {
985 System.out.println("\n@@@@@\n" + XSLTUtil.getInterfaceStringsAsJavascript("default", "en", "dse", "gs.text") + "@@@@@\n");
986 }
987}
Note: See TracBrowser for help on using the repository browser.