001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.util;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.StringReader;
025import java.io.StringWriter;
026import java.net.URISyntaxException;
027import java.net.URL;
028import java.util.ArrayList;
029import java.util.zip.DataFormatException;
030import java.util.zip.Deflater;
031import java.util.zip.Inflater;
032
033import javax.xml.parsers.DocumentBuilder;
034import javax.xml.parsers.DocumentBuilderFactory;
035import javax.xml.parsers.ParserConfigurationException;
036import javax.xml.transform.OutputKeys;
037import javax.xml.transform.Transformer;
038import javax.xml.transform.TransformerConfigurationException;
039import javax.xml.transform.TransformerException;
040import javax.xml.transform.TransformerFactory;
041import javax.xml.transform.dom.DOMSource;
042import javax.xml.transform.stream.StreamResult;
043
044import org.w3c.dom.Attr;
045import org.w3c.dom.Document;
046import org.w3c.dom.DocumentType;
047import org.w3c.dom.Element;
048import org.w3c.dom.NamedNodeMap;
049import org.w3c.dom.Node;
050import org.w3c.dom.NodeList;
051import org.xml.sax.InputSource;
052import org.xml.sax.SAXException;
053
054import icy.file.FileUtil;
055import icy.network.AuthenticationInfo;
056import icy.network.NetworkUtil;
057import icy.network.URLUtil;
058import icy.system.IcyExceptionHandler;
059import icy.type.DataType;
060import icy.type.collection.array.ArrayUtil;
061
062/**
063 * XML utilities class (parse, read, create and write XML documents).
064 * 
065 * @author Stephane
066 */
067public class XMLUtil
068{
069    public static final String FILE_EXTENSION = "xml";
070    public static final String FILE_DOT_EXTENSION = "." + FILE_EXTENSION;
071
072    public static final String NODE_ROOT_NAME = "root";
073
074    private static final String ATTR_NAME_NAME = "name";
075    private static final String ATTR_VALUE_NAME = "value";
076
077    // static document builder factory
078    private static DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
079    // static transformer factory
080    private static TransformerFactory transformerFactory = TransformerFactory.newInstance();
081    // static Deflater
082    // private static Deflater deflater = new Deflater(2, true);
083    private static Deflater deflater = new Deflater(2);
084    // static Inflater
085    // private static Inflater inflater = new Inflater(true);
086    private static Inflater inflater = new Inflater();
087
088    static
089    {
090        try
091        {
092            docBuilderFactory.setNamespaceAware(false);
093            docBuilderFactory.setValidating(false);
094            docBuilderFactory.setFeature("http://xml.org/sax/features/namespaces", false);
095            docBuilderFactory.setFeature("http://xml.org/sax/features/validation", false);
096            docBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
097            docBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
098        }
099        catch (Exception e)
100        {
101            // ignore this
102        }
103    }
104
105    // private static synchronized void init()
106    // {
107    // // initialize static builder
108    // if (docBuilder == null)
109    // docBuilder = createDocumentBuilder();
110    // // initialize static transformer
111    // if (transformer == null)
112    // transformer = createTransformer();
113    // }
114    // docBuilder = createDocumentBuilder();
115    // transformer = createTransformer();
116
117    /**
118     * Create and returns a new DocumentBuilder.
119     */
120    public static DocumentBuilder createDocumentBuilder()
121    {
122        try
123        {
124            return docBuilderFactory.newDocumentBuilder();
125        }
126        catch (ParserConfigurationException e)
127        {
128            e.printStackTrace();
129            return null;
130        }
131    }
132
133    /**
134     * Create and returns a new Transformer.
135     */
136    public static Transformer createTransformer()
137    {
138        final Transformer result;
139
140        try
141        {
142            result = transformerFactory.newTransformer();
143        }
144        catch (TransformerConfigurationException e)
145        {
146            IcyExceptionHandler.showErrorMessage(e, true, true);
147            return null;
148        }
149
150        result.setOutputProperty(OutputKeys.METHOD, "xml");
151        result.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
152        result.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
153        result.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
154        result.setOutputProperty(OutputKeys.INDENT, "yes");
155
156        return result;
157    }
158
159    /**
160     * Create and returns a new Transformer.
161     */
162    public static Transformer createTransformerSafe() throws TransformerConfigurationException
163    {
164        final Transformer result = transformerFactory.newTransformer();
165
166        result.setOutputProperty(OutputKeys.METHOD, "xml");
167        result.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
168        result.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
169        result.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
170        result.setOutputProperty(OutputKeys.INDENT, "yes");
171
172        return result;
173    }
174
175    /**
176     * Create and return an empty XML Document.
177     */
178    public static Document createDocument(boolean createRoot)
179    {
180        final DocumentBuilder docBuilder = createDocumentBuilder();
181
182        // an error occurred
183        if (docBuilder == null)
184            return null;
185
186        // create document
187        final Document result = docBuilder.newDocument();
188
189        // add default "root" element if wanted
190        if (createRoot)
191            createRootElement(result);
192
193        return result;
194    }
195
196    /**
197     * Parse the specified string and convert it to XML Document (throw an exception if an error occurred).
198     * 
199     * @throws IOException
200     * @throws SAXException
201     */
202    public static Document createDocument(String xmlString) throws SAXException, IOException
203    {
204        final DocumentBuilder docBuilder = createDocumentBuilder();
205
206        // an error occurred
207        if (docBuilder == null)
208            return null;
209
210        return docBuilder.parse(new InputSource(new StringReader(filterString(xmlString))));
211    }
212
213    /**
214     * @deprecated Use {@link #createDocument(String)} instead.
215     */
216    @Deprecated
217    public static Document getDocument(String xmlString)
218    {
219        final DocumentBuilder docBuilder = createDocumentBuilder();
220
221        // an error occurred
222        if (docBuilder == null)
223            return null;
224
225        try
226        {
227            return docBuilder.parse(new InputSource(new StringReader(filterString(xmlString))));
228        }
229        catch (Exception e)
230        {
231            IcyExceptionHandler.showErrorMessage(e, true);
232        }
233
234        // return empty document
235        return createDocument(false);
236    }
237
238    /**
239     * @deprecated Use {@link #createDocument(String)} instead.
240     */
241    @Deprecated
242    public static Document getDocumentSafe(String xmlString) throws SAXException, IOException
243    {
244        return createDocument(xmlString);
245    }
246
247    /**
248     * Load XML Document from specified path.<br>
249     * Return null if no document can be loaded.
250     */
251    public static Document loadDocument(String path)
252    {
253        return loadDocument(path, null, false);
254    }
255
256    /**
257     * Load XML Document from specified path.<br>
258     * Return null if no document can be loaded.
259     */
260    public static Document loadDocument(String path, boolean showError)
261    {
262        return loadDocument(path, null, showError);
263    }
264
265    /**
266     * Load XML Document from specified path with specified authentication.<br>
267     * Return null if no document can be loaded.
268     */
269    public static Document loadDocument(String path, AuthenticationInfo auth, boolean showError)
270    {
271        if (StringUtil.isEmpty(path))
272        {
273            if (showError)
274                System.err.println("XMLUtil.loadDocument('" + path + "') error: empty path !");
275
276            return null;
277        }
278
279        final URL url = URLUtil.getURL(path);
280
281        // load from URL
282        if (url != null)
283            return loadDocument(url, auth, showError);
284
285        // try to load from file instead (no authentication needed then)
286        return loadDocument(new File(path), showError);
287    }
288
289    /**
290     * Load XML Document from specified file.<br>
291     * Return null if no document can be loaded.
292     */
293    public static Document loadDocument(File f)
294    {
295        return loadDocument(f, false);
296    }
297
298    /**
299     * Load XML Document from specified file.<br>
300     * Return null if no document can be loaded.
301     */
302    public static Document loadDocument(File f, boolean showError)
303    {
304        if ((f == null) || !f.exists())
305        {
306            if (showError)
307                System.err.println("XMLUtil.loadDocument('" + f + "') error: file not found !");
308
309            return null;
310        }
311
312        final DocumentBuilder builder = createDocumentBuilder();
313
314        if (builder != null)
315        {
316            try
317            {
318                return builder.parse(f);
319            }
320            catch (Exception e)
321            {
322                if (showError)
323                {
324                    System.err.println("XMLUtil.loadDocument('" + f.getPath() + "') error:");
325                    IcyExceptionHandler.showErrorMessage(e, false);
326                }
327            }
328        }
329
330        return null;
331    }
332
333    /**
334     * Load XML Document from specified URL.<br>
335     * Return null if no document can be loaded.
336     */
337    public static Document loadDocument(URL url)
338    {
339        return loadDocument(url, null, false);
340    }
341
342    /**
343     * Load XML Document from specified URL.<br>
344     * Return null if no document can be loaded.
345     */
346    public static Document loadDocument(URL url, boolean showError)
347    {
348        return loadDocument(url, null, showError);
349    }
350
351    /**
352     * Load XML Document from specified URL with authentication informations.<br>
353     * Return null if no document can be loaded.
354     */
355    public static Document loadDocument(URL url, AuthenticationInfo auth, boolean showError)
356    {
357        // use file loading if possible
358        if (URLUtil.isFileURL(url))
359        {
360            File f;
361
362            try
363            {
364                f = new File(url.toURI());
365            }
366            catch (URISyntaxException e)
367            {
368                f = new File(url.getPath());
369            }
370
371            return loadDocument(f);
372        }
373
374        final DocumentBuilder builder = createDocumentBuilder();
375
376        if (builder != null)
377        {
378            final InputStream ip = NetworkUtil.getInputStream(url, auth, true, showError);
379
380            if (ip != null)
381            {
382                try
383                {
384                    return builder.parse(ip);
385                }
386                catch (Exception e)
387                {
388                    System.err.println("XMLUtil.loadDocument('" + url + "') error :");
389                    IcyExceptionHandler.showErrorMessage(e, false);
390                }
391                finally
392                {
393                    try
394                    {
395                        ip.close();
396                    }
397                    catch (IOException e)
398                    {
399                        // ignore
400                    }
401                }
402            }
403            else if (showError)
404                System.err.println("XMLUtil.loadDocument('" + url + "') failed.");
405        }
406
407        return null;
408    }
409
410    /**
411     * Save the specified XML Document to specified filename.<br>
412     * Return false if an error occurred.
413     */
414    public static boolean saveDocument(Document doc, String filename)
415    {
416        return saveDocument(doc, FileUtil.createFile(filename));
417    }
418
419    /**
420     * Save the specified XML Document to specified file.<br>
421     * Return false if an error occurred.
422     */
423    public static boolean saveDocument(Document doc, File f)
424    {
425        if ((doc == null) || (f == null))
426        {
427            System.err.println("XMLUtil.saveDocument(...) error: specified document or file is null !");
428
429            return false;
430        }
431
432        final Transformer transformer = createTransformer();
433
434        // an error occurred
435        if (transformer == null)
436            return false;
437
438        doc.normalizeDocument();
439
440        final DocumentType doctype = doc.getDoctype();
441        final DOMSource domSource = new DOMSource(doc);
442        final StreamResult streamResult = new StreamResult(f.getAbsolutePath());
443
444        try
445        {
446            if (doctype != null)
447            {
448                transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, doctype.getPublicId());
449                transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doctype.getSystemId());
450            }
451
452            transformer.transform(domSource, streamResult);
453
454            return true;
455        }
456        catch (Exception e)
457        {
458            IcyExceptionHandler.showErrorMessage(e, true);
459        }
460
461        return false;
462    }
463
464    /**
465     * Return the XML String from the specified document.
466     * 
467     * @throws TransformerException
468     */
469    public static String getXMLString(Document document) throws TransformerException
470    {
471        if (document == null)
472            return "";
473
474        final Transformer transformer = createTransformerSafe();
475        final StringWriter writer = new StringWriter();
476
477        transformer.transform(new DOMSource(document), new StreamResult(writer));
478
479        return writer.toString();
480    }
481
482    /**
483     * Create root element for specified document if it does not already exist and return it
484     */
485    public static Element createRootElement(Document doc)
486    {
487        return createRootElement(doc, NODE_ROOT_NAME);
488    }
489
490    /**
491     * Create root element for specified document if it does not already exist and return it
492     */
493    public static Element createRootElement(Document doc, String name)
494    {
495        return getRootElement(doc, true, name);
496    }
497
498    /**
499     * Return the root element for specified document<br>
500     * Create if it does not already exist with the specified name
501     */
502    private static Element getRootElement(Document doc, boolean create, String name)
503    {
504        if (doc != null)
505        {
506            Element result = doc.getDocumentElement();
507
508            if ((result == null) && create)
509            {
510                result = doc.createElement(name);
511                doc.appendChild(result);
512            }
513
514            return result;
515        }
516
517        return null;
518    }
519
520    /**
521     * Return the root element for specified document<br>
522     * Create if it does not already exist with the default {@link #NODE_ROOT_NAME}
523     */
524    public static Element getRootElement(Document doc, boolean create)
525    {
526        return getRootElement(doc, create, NODE_ROOT_NAME);
527    }
528
529    /**
530     * Return the root element for specified document (null if not found)<br>
531     */
532    public static Element getRootElement(Document doc)
533    {
534        return getRootElement(doc, false);
535    }
536
537    /**
538     * Get parent element of specified element
539     */
540    public static Element getParentElement(Element element)
541    {
542        Node parent = element.getParentNode();
543
544        while (parent != null)
545        {
546            if (parent instanceof Element)
547                return (Element) parent;
548
549            parent = parent.getParentNode();
550        }
551
552        return null;
553    }
554
555    /**
556     * Get all child node of specified node.
557     */
558    @SuppressWarnings("null")
559    public static ArrayList<Node> getChildren(Node node)
560    {
561        final ArrayList<Node> result = new ArrayList<Node>();
562        int tries = 3;
563        RuntimeException exception = null;
564
565        // sometime the XML library fails so we make several attempts
566        while (tries > 0)
567        {
568            try
569            {
570                final NodeList nodeList = node.getChildNodes();
571
572                if (nodeList != null)
573                {
574                    for (int i = 0; i < nodeList.getLength(); i++)
575                    {
576                        final Node n = nodeList.item(i);
577
578                        if (n != null)
579                            result.add(n);
580                    }
581                }
582
583                return result;
584            }
585            catch (RuntimeException e)
586            {
587                // try again
588                exception = e;
589                tries--;
590            }
591        }
592
593        throw exception;
594    }
595
596    /**
597     * Get the first child node with specified name from node.<br>
598     * Return null if not found.
599     */
600    @SuppressWarnings("null")
601    public static Node getChild(Node node, String name)
602    {
603        int tries = 3;
604        RuntimeException exception = null;
605
606        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
607        while (tries > 0)
608        {
609            final NodeList nodeList = node.getChildNodes();
610
611            try
612            {
613                if (nodeList != null)
614                {
615                    for (int i = 0; i < nodeList.getLength(); i++)
616                    {
617                        final Node n = nodeList.item(i);
618
619                        if ((n != null) && n.getNodeName().equals(name))
620                            return n;
621                    }
622                }
623
624                return null;
625            }
626            catch (RuntimeException e)
627            {
628                // try again
629                exception = e;
630                tries--;
631            }
632        }
633
634        throw exception;
635    }
636
637    /**
638     * Get all child nodes with specified name from node.
639     */
640    @SuppressWarnings("null")
641    public static ArrayList<Node> getChildren(Node node, String name)
642    {
643        final ArrayList<Node> result = new ArrayList<Node>();
644        int tries = 3;
645        RuntimeException exception = null;
646
647        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
648        while (tries > 0)
649        {
650            final NodeList nodeList = node.getChildNodes();
651
652            try
653            {
654                if (nodeList != null)
655                {
656                    for (int i = 0; i < nodeList.getLength(); i++)
657                    {
658                        final Node n = nodeList.item(i);
659
660                        if ((n != null) && n.getNodeName().equals(name))
661                            result.add(n);
662                    }
663                }
664
665                return result;
666            }
667            catch (RuntimeException e)
668            {
669                // try again
670                exception = e;
671                tries--;
672            }
673        }
674
675        throw exception;
676    }
677
678    /**
679     * @deprecated Use {@link #getChildren(Node)} instead.
680     */
681    @Deprecated
682    public static ArrayList<Node> getSubNodes(Node node)
683    {
684        return getChildren(node);
685    }
686
687    /**
688     * @deprecated Use {@link #getChild(Node, String)} instead.
689     */
690    @Deprecated
691    public static Node getSubNode(Node node, String name)
692    {
693        return getChild(node, name);
694    }
695
696    /**
697     * @deprecated Use {@link #getChildren(Node, String)} instead.
698     */
699    @Deprecated
700    public static ArrayList<Node> getSubNodes(Node node, String name)
701    {
702        return getChildren(node, name);
703    }
704
705    /**
706     * Get all child element of specified node.
707     */
708    @SuppressWarnings("null")
709    public static ArrayList<Element> getElements(Node node)
710    {
711        final ArrayList<Element> result = new ArrayList<Element>();
712        int tries = 3;
713        RuntimeException exception = null;
714
715        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
716        while (tries > 0)
717        {
718            final NodeList nodeList = node.getChildNodes();
719
720            try
721            {
722                if (nodeList != null)
723                {
724                    for (int i = 0; i < nodeList.getLength(); i++)
725                    {
726                        final Node n = nodeList.item(i);
727
728                        if (n instanceof Element)
729                            result.add((Element) n);
730                    }
731                }
732
733                return result;
734            }
735            catch (RuntimeException e)
736            {
737                // try again
738                exception = e;
739                tries--;
740            }
741        }
742
743        throw exception;
744    }
745
746    /**
747     * Get the first child element with specified name from node.<br>
748     * Return null if not found.
749     */
750    @SuppressWarnings("null")
751    public static Element getElement(Node node, String name)
752    {
753        if (node == null)
754            return null;
755
756        final String filteredName = filterString(name);
757        int tries = 3;
758        RuntimeException exception = null;
759
760        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
761        while (tries > 0)
762        {
763            try
764            {
765                final NodeList nodeList = node.getChildNodes();
766
767                if (nodeList != null)
768                {
769                    for (int i = 0; i < nodeList.getLength(); i++)
770                    {
771                        final Node n = nodeList.item(i);
772
773                        if ((n instanceof Element) && n.getNodeName().equals(filteredName))
774                            return (Element) n;
775                    }
776                }
777
778                return null;
779            }
780            catch (RuntimeException e)
781            {
782                // try again
783                exception = e;
784                tries--;
785            }
786        }
787
788        throw exception;
789    }
790
791    /**
792     * Get all child element with specified name of specified node.
793     */
794    @SuppressWarnings("null")
795    public static ArrayList<Element> getElements(Node node, String name)
796    {
797        final ArrayList<Element> result = new ArrayList<Element>();
798        final String filteredName = filterString(name);
799        int tries = 3;
800        RuntimeException exception = null;
801
802        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
803        while (tries > 0)
804        {
805            final NodeList nodeList = node.getChildNodes();
806
807            try
808            {
809                if (nodeList != null)
810                {
811                    for (int i = 0; i < nodeList.getLength(); i++)
812                    {
813                        final Node n = nodeList.item(i);
814
815                        if ((n instanceof Element) && n.getNodeName().equals(filteredName))
816                            result.add((Element) n);
817                    }
818                }
819                return result;
820            }
821            catch (RuntimeException e)
822            {
823                // try again
824                exception = e;
825                tries--;
826            }
827        }
828
829        throw exception;
830    }
831
832    /**
833     * @deprecated Use {@link #getElements(Node)} instead.
834     */
835    @Deprecated
836    public static ArrayList<Element> getSubElements(Node node)
837    {
838        return getElements(node);
839    }
840
841    /**
842     * @deprecated Use {@link #getElement(Node, String)} instead.
843     */
844    @Deprecated
845    public static Element getSubElement(Node node, String name)
846    {
847        return getElement(node, name);
848    }
849
850    /**
851     * @deprecated Use {@link #getElements(Node, String)} instead.
852     */
853    @Deprecated
854    public static ArrayList<Element> getSubElements(Node node, String name)
855    {
856        return getElements(node, name);
857    }
858
859    /**
860     * Get all child element with specified type (name) from specified node.
861     */
862    @SuppressWarnings("null")
863    public static ArrayList<Element> getGenericElements(Node node, String type)
864    {
865        final ArrayList<Element> result = new ArrayList<Element>();
866        final String filteredType = filterString(type);
867        int tries = 3;
868        RuntimeException exception = null;
869
870        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
871        while (tries > 0)
872        {
873            final NodeList nodeList = node.getChildNodes();
874
875            try
876            {
877                if (nodeList != null)
878                {
879                    for (int i = 0; i < nodeList.getLength(); i++)
880                    {
881                        final Node n = nodeList.item(i);
882
883                        if ((n instanceof Element) && n.getNodeName().equals(filteredType))
884                            result.add((Element) n);
885                    }
886                }
887
888                return result;
889            }
890            catch (RuntimeException e)
891            {
892                // try again
893                exception = e;
894                tries--;
895            }
896        }
897
898        throw exception;
899    }
900
901    /**
902     * Get all child element with specified type (name) and name ('name attribute value')
903     * from specified node.
904     */
905    @SuppressWarnings("null")
906    public static ArrayList<Element> getGenericElements(Node node, String type, String name)
907    {
908        final ArrayList<Element> result = new ArrayList<Element>();
909        final String filteredName = filterString(name);
910        final String filteredType = filterString(type);
911        int tries = 3;
912        RuntimeException exception = null;
913
914        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
915        while (tries > 0)
916        {
917            final NodeList nodeList = node.getChildNodes();
918
919            try
920            {
921                if (nodeList != null)
922                {
923                    for (int i = 0; i < nodeList.getLength(); i++)
924                    {
925                        final Node n = nodeList.item(i);
926
927                        if ((n instanceof Element) && n.getNodeName().equals(filteredType))
928                        {
929                            final Element element = (Element) n;
930
931                            if (element.getAttribute(ATTR_NAME_NAME).equals(filteredName))
932                                result.add(element);
933                        }
934                    }
935                }
936
937                return result;
938            }
939            catch (RuntimeException e)
940            {
941                // try again
942                exception = e;
943                tries--;
944            }
945        }
946
947        throw exception;
948    }
949
950    /**
951     * @deprecated Use {@link #getGenericElements(Node, String)} instead.
952     */
953    @Deprecated
954    public static ArrayList<Element> getSubGenericElements(Node node, String type)
955    {
956        return getGenericElements(node, type);
957    }
958
959    /**
960     * @deprecated Use {@link #getGenericElements(Node, String, String)} instead.
961     */
962    @Deprecated
963    public static ArrayList<Element> getSubGenericElements(Node node, String type, String name)
964    {
965        return getGenericElements(node, type, name);
966    }
967
968    /**
969     * Get child element with specified type (name) and name ('name attribute value')
970     * from specified node.
971     */
972    @SuppressWarnings("null")
973    public static Element getGenericElement(Node node, String type, String name)
974    {
975        final String filteredName = filterString(name);
976        final String filteredType = filterString(type);
977        int tries = 3;
978        RuntimeException exception = null;
979
980        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
981        while (tries > 0)
982        {
983            final NodeList nodeList = node.getChildNodes();
984
985            try
986            {
987                if (nodeList != null)
988                {
989                    for (int i = 0; i < nodeList.getLength(); i++)
990                    {
991                        final Node n = nodeList.item(i);
992
993                        if ((n instanceof Element) && n.getNodeName().equals(filteredType))
994                        {
995                            final Element element = (Element) n;
996
997                            if (element.getAttribute(ATTR_NAME_NAME).equals(filteredName))
998                                return element;
999                        }
1000                    }
1001                }
1002
1003                return null;
1004            }
1005            catch (RuntimeException e)
1006            {
1007                // try again
1008                exception = e;
1009                tries--;
1010            }
1011        }
1012
1013        throw exception;
1014    }
1015
1016    /**
1017     * Get name of specified generic element
1018     */
1019    public static String getGenericElementName(Element element)
1020    {
1021        if (element != null)
1022            return element.getAttribute(ATTR_NAME_NAME);
1023
1024        return "";
1025    }
1026
1027    /**
1028     * Get value of specified generic element
1029     */
1030    public static String getGenericElementValue(Element element, String def)
1031    {
1032        return getAttributeValue(element, ATTR_VALUE_NAME, def);
1033    }
1034
1035    /**
1036     * Get all attributes of the specified element
1037     */
1038    public static ArrayList<Attr> getAllAttributes(Element element)
1039    {
1040        final NamedNodeMap nodeMap = element.getAttributes();
1041        final ArrayList<Attr> result = new ArrayList<Attr>();
1042
1043        for (int i = 0; i < nodeMap.getLength(); i++)
1044            result.add((Attr) nodeMap.item(i));
1045
1046        return result;
1047    }
1048
1049    private static boolean getBoolean(String value, boolean def)
1050    {
1051        return StringUtil.parseBoolean(value, def);
1052    }
1053
1054    private static int getInt(String value, int def)
1055    {
1056        return StringUtil.parseInt(value, def);
1057    }
1058
1059    private static long getLong(String value, long def)
1060    {
1061        return StringUtil.parseLong(value, def);
1062    }
1063
1064    private static float getFloat(String value, float def)
1065    {
1066        return StringUtil.parseFloat(value, def);
1067    }
1068
1069    private static double getDouble(String value, double def)
1070    {
1071        return StringUtil.parseDouble(value, def);
1072    }
1073
1074    public static byte[] getBytes(String value, byte[] def) throws DataFormatException
1075    {
1076        if (value == null)
1077            return def;
1078
1079        // get packed byte data
1080        final byte[] result = (byte[]) ArrayUtil.stringToArray1D(value, DataType.BYTE, true, ":");
1081
1082        synchronized (inflater)
1083        {
1084            // unpack and return
1085            return ZipUtil.unpack(inflater, result);
1086        }
1087    }
1088
1089    private static String toString(boolean value)
1090    {
1091        return StringUtil.toString(value);
1092    }
1093
1094    private static String toString(int value)
1095    {
1096        return StringUtil.toString(value);
1097    }
1098
1099    private static String toString(long value)
1100    {
1101        return StringUtil.toString(value);
1102    }
1103
1104    private static String toString(float value)
1105    {
1106        return StringUtil.toString(value);
1107    }
1108
1109    private static String toString(double value)
1110    {
1111        return StringUtil.toString(value);
1112    }
1113
1114    public static String toString(byte[] value)
1115    {
1116        final byte[] packed;
1117
1118        synchronized (deflater)
1119        {
1120            packed = ZipUtil.pack(deflater, value, -1);
1121        }
1122
1123        // pack data and convert to string
1124        return ArrayUtil.array1DToString(packed, false, true, ":", -1);
1125    }
1126
1127    /**
1128     * Get an attribute from the specified Element
1129     */
1130    public static Attr getAttribute(Element element, String attribute)
1131    {
1132        if (element != null)
1133            return element.getAttributeNode(attribute);
1134
1135        return null;
1136    }
1137
1138    /**
1139     * Get attribute value from the specified Element.<br>
1140     * If no attribute found 'def' value is returned.
1141     */
1142    @SuppressWarnings("null")
1143    public static String getAttributeValue(Element element, String attribute, String def)
1144    {
1145        if (element == null)
1146            return def;
1147
1148        final String filteredAttr = filterString(attribute);
1149        int tries = 3;
1150        RuntimeException exception = null;
1151
1152        // sometime the XML library fails so we make several attempts
1153        while (tries > 0)
1154        {
1155            try
1156            {
1157                final Attr attr = element.getAttributeNode(filteredAttr);
1158
1159                if (attr != null)
1160                    return attr.getValue();
1161
1162                return def;
1163            }
1164            catch (RuntimeException e)
1165            {
1166                // try again
1167                exception = e;
1168                tries--;
1169            }
1170        }
1171
1172        throw exception;
1173    }
1174
1175    /**
1176     * Get attribute value as Boolean from the specified Element.<br>
1177     * If no attribute found 'def' value is returned.
1178     */
1179    public static boolean getAttributeBooleanValue(Element element, String attribute, boolean def)
1180    {
1181        return getBoolean(getAttributeValue(element, attribute, ""), def);
1182    }
1183
1184    /**
1185     * Get attribute value as byte array from the specified Element.<br>
1186     * If the attribute is not found 'def' value is returned.<br>
1187     * If an error occurred or if element is <code>null</code> then <code>null</code> is returned.
1188     */
1189    public static byte[] getAttributeBytesValue(Element element, String attribute, byte[] def)
1190    {
1191        try
1192        {
1193            return getBytes(getAttributeValue(element, attribute, ""), def);
1194        }
1195        catch (Exception e)
1196        {
1197            if (e instanceof RuntimeException)
1198                throw (RuntimeException) e;
1199
1200            IcyExceptionHandler.showErrorMessage(e, true);
1201            return null;
1202        }
1203    }
1204
1205    /**
1206     * Get attribute value as integer from the specified Element.<br>
1207     * If no attribute found 'def' value is returned.
1208     */
1209    public static int getAttributeIntValue(Element element, String attribute, int def)
1210    {
1211        return getInt(getAttributeValue(element, attribute, ""), def);
1212    }
1213
1214    /**
1215     * Get attribute value as long from the specified Element.<br>
1216     * If no attribute found 'def' value is returned.
1217     */
1218    public static long getAttributeLongValue(Element element, String attribute, long def)
1219    {
1220        return getLong(getAttributeValue(element, attribute, ""), def);
1221    }
1222
1223    /**
1224     * Get attribute value as float from the specified Element.<br>
1225     * If no attribute found 'def' value is returned.
1226     */
1227    public static float getAttributeFloatValue(Element element, String attribute, float def)
1228    {
1229        return getFloat(getAttributeValue(element, attribute, ""), def);
1230    }
1231
1232    /**
1233     * Get attribute value as double from the specified Element.<br>
1234     * If no attribute found 'def' value is returned.
1235     */
1236    public static double getAttributeDoubleValue(Element element, String attribute, double def)
1237    {
1238        return getDouble(getAttributeValue(element, attribute, ""), def);
1239    }
1240
1241    /**
1242     * Get first value (value of first child) from the specified Element.<br>
1243     * If no value found 'def' value is returned.
1244     */
1245    @SuppressWarnings("null")
1246    public static String getFirstValue(Element element, String def)
1247    {
1248        if (element == null)
1249            return def;
1250
1251        int tries = 3;
1252        RuntimeException exception = null;
1253
1254        // sometime the XML library fails so we make several attempts
1255        while (tries > 0)
1256        {
1257            try
1258            {
1259                final Node child = element.getFirstChild();
1260
1261                if (child != null)
1262                    return child.getNodeValue();
1263
1264                return def;
1265            }
1266            catch (RuntimeException e)
1267            {
1268                // try again
1269                exception = e;
1270                tries--;
1271            }
1272        }
1273
1274        throw exception;
1275    }
1276
1277    /**
1278     * Get all values (value of all child) from the specified Element.<br>
1279     * If no value found 'def' value is returned.
1280     */
1281    @SuppressWarnings("null")
1282    public static String getAllValues(Element element, String def)
1283    {
1284        if (element == null)
1285            return def;
1286
1287        int tries = 3;
1288        RuntimeException exception = null;
1289
1290        // sometime the XML library fails so we make several attempts
1291        while (tries > 0)
1292        {
1293            try
1294            {
1295                final StringBuilder str = new StringBuilder();
1296
1297                Node child = element.getFirstChild();
1298                while (child != null)
1299                {
1300                    str.append(child.getNodeValue());
1301                    child = child.getNextSibling();
1302                }
1303
1304                return str.toString();
1305            }
1306            catch (RuntimeException e)
1307            {
1308                // try again
1309                exception = e;
1310                tries--;
1311            }
1312        }
1313
1314        throw exception;
1315    }
1316
1317    /**
1318     * Get all values (value of all child) as String from the specified Element.<br>
1319     * If no value found 'def' value is returned.
1320     */
1321    public static String getValue(Element element, String def)
1322    {
1323        return getAllValues(element, def);
1324    }
1325
1326    /**
1327     * Get all values (value of all child) as Boolean from the specified Element.
1328     */
1329    public static boolean getBooleanValue(Element element, boolean def)
1330    {
1331        return getBoolean(getFirstValue(element, ""), def);
1332    }
1333
1334    /**
1335     * Get value as integer from the specified Element.<br>
1336     * If no integer value found 'def' value is returned.
1337     */
1338    public static int getIntValue(Element element, int def)
1339    {
1340        return getInt(getFirstValue(element, ""), def);
1341    }
1342
1343    /**
1344     * Get value as long from the specified Element.<br>
1345     * If no integer value found 'def' value is returned.
1346     */
1347    public static long getLongValue(Element element, long def)
1348    {
1349        return getLong(getFirstValue(element, ""), def);
1350    }
1351
1352    /**
1353     * Get value as float from the specified Element.<br>
1354     * If no float value found 'def' value is returned.
1355     */
1356    public static float getFloatValue(Element element, float def)
1357    {
1358        return getFloat(getFirstValue(element, ""), def);
1359    }
1360
1361    /**
1362     * Get value as double from the specified Element.<br>
1363     * If no double value found 'def' value is returned.
1364     */
1365    public static double getDoubleValue(Element element, double def)
1366    {
1367        return getDouble(getFirstValue(element, ""), def);
1368    }
1369
1370    /**
1371     * Get value as byte array from the specified Element.<br>
1372     * If no byte array value found 'def' value is returned.<br>
1373     * Return <code>null</code> if an error happened.
1374     */
1375    public static byte[] getBytesValue(Element element, byte[] def)
1376    {
1377        try
1378        {
1379            return getBytes(getFirstValue(element, ""), def);
1380        }
1381        catch (Exception e)
1382        {
1383            if (e instanceof RuntimeException)
1384                throw (RuntimeException) e;
1385
1386            IcyExceptionHandler.showErrorMessage(e, true);
1387            return null;
1388        }
1389    }
1390
1391    /**
1392     * Get first element value from the specified node.<br>
1393     * If no value found 'def' value is returned.
1394     */
1395    public static String getElementFirstValue(Node node, String name, String def)
1396    {
1397        return getFirstValue(getElement(node, name), def);
1398    }
1399
1400    /**
1401     * Get all element values from the specified node.<br>
1402     * If no value found 'def' value is returned.
1403     */
1404    public static String getElementAllValues(Node node, String name, String def)
1405    {
1406        return getAllValues(getElement(node, name), def);
1407    }
1408
1409    /**
1410     * Get element value as string from the specified node.<br>
1411     * If no value found 'def' value is returned.
1412     */
1413    public static String getElementValue(Node node, String name, String def)
1414    {
1415        return getValue(getElement(node, name), def);
1416    }
1417
1418    /**
1419     * Get element value as boolean from the specified node.
1420     */
1421    public static boolean getElementBooleanValue(Node node, String name, boolean def)
1422    {
1423        return getBoolean(getElementValue(node, name, ""), def);
1424    }
1425
1426    /**
1427     * Get element value as integer from the specified node.<br>
1428     * If no integer value found 'def' value is returned.
1429     */
1430    public static int getElementIntValue(Node node, String name, int def)
1431    {
1432        return getInt(getElementValue(node, name, ""), def);
1433    }
1434
1435    /**
1436     * Get element value as long from the specified node.<br>
1437     * If no integer value found 'def' value is returned.
1438     */
1439    public static long getElementLongValue(Node node, String name, long def)
1440    {
1441        return getLong(getElementValue(node, name, ""), def);
1442    }
1443
1444    /**
1445     * Get element value as float from the specified node.<br>
1446     * If no float value found 'def' value is returned.
1447     */
1448    public static float getElementFloatValue(Node node, String name, float def)
1449    {
1450        return getFloat(getElementValue(node, name, ""), def);
1451    }
1452
1453    /**
1454     * Get element value as double from the specified node.<br>
1455     * If no double value found 'def' value is returned.
1456     */
1457    public static double getElementDoubleValue(Node node, String name, double def)
1458    {
1459        return getDouble(getElementValue(node, name, ""), def);
1460    }
1461
1462    /**
1463     * Get element value as byte array from the specified node.<br>
1464     * If no byte array value found 'def' value is returned.<br>
1465     * Return <code>null</code> if an error happened.
1466     */
1467    public static byte[] getElementBytesValue(Node node, String name, byte[] def)
1468    {
1469        try
1470        {
1471            return getBytes(getElementValue(node, name, ""), def);
1472        }
1473        catch (Exception e)
1474        {
1475            if (e instanceof RuntimeException)
1476                throw (RuntimeException) e;
1477
1478            IcyExceptionHandler.showErrorMessage(e, true);
1479            return null;
1480        }
1481    }
1482
1483    /**
1484     * Get value ('value' attribute value) from element with specified type
1485     * and name ('name' attribute value).<br>
1486     * If no value found 'def' value is returned.
1487     */
1488    public static String getGenericElementValue(Node node, String type, String name, String def)
1489    {
1490        return getGenericElementValue(getGenericElement(node, type, name), def);
1491    }
1492
1493    /**
1494     * Get value ('value' attribute value) as boolean from element with specified type
1495     * and name ('name' attribute value).<br>
1496     * If no byte array value found 'def' value is returned.
1497     */
1498    public static boolean getGenericElementBooleanValue(Node node, String type, String name, boolean def)
1499    {
1500        return getBoolean(getGenericElementValue(node, type, name, ""), def);
1501    }
1502
1503    /**
1504     * Get value ('value' attribute value) as integer from element with specified type
1505     * and name ('name' attribute value).<br>
1506     * If no integer value found 'def' value is returned.
1507     */
1508    public static int getGenericElementIntValue(Node node, String type, String name, int def)
1509    {
1510        return getInt(getGenericElementValue(node, type, name, ""), def);
1511    }
1512
1513    /**
1514     * Get value ('value' attribute value) as long from element with specified type
1515     * and name ('name' attribute value).<br>
1516     * If no integer value found 'def' value is returned.
1517     */
1518    public static long getGenericElementLongValue(Node node, String type, String name, long def)
1519    {
1520        return getLong(getGenericElementValue(node, type, name, ""), def);
1521    }
1522
1523    /**
1524     * Get value ('value' attribute value) as float from element with specified type
1525     * and name ('name' attribute value).<br>
1526     * If no float value found 'def' value is returned.
1527     */
1528    public static float getGenericElementFloatValue(Node node, String type, String name, float def)
1529    {
1530        return getFloat(getGenericElementValue(node, type, name, ""), def);
1531    }
1532
1533    /**
1534     * Get value ('value' attribute value) as double from element with specified type
1535     * and name ('name' attribute value).<br>
1536     * If no double value found 'def' value is returned.
1537     */
1538    public static double getGenericElementDoubleValue(Node node, String type, String name, double def)
1539    {
1540        return getDouble(getGenericElementValue(node, type, name, ""), def);
1541    }
1542
1543    /**
1544     * Get value ('value' attribute value) as byte array from element with specified type
1545     * and name ('name' attribute value).<br>
1546     * If no byte array value found 'def' value is returned.<br>
1547     * Return <code>null</code> if an error happened.
1548     */
1549    public static byte[] getGenericElementBytesValue(Node node, String type, String name, byte[] def)
1550    {
1551        try
1552        {
1553            return getBytes(getElementValue(node, name, ""), def);
1554        }
1555        catch (Exception e)
1556        {
1557            if (e instanceof RuntimeException)
1558                throw (RuntimeException) e;
1559
1560            IcyExceptionHandler.showErrorMessage(e, true);
1561            return null;
1562        }
1563    }
1564
1565    /**
1566     * Add the specified node to specified parent node
1567     */
1568    public static Node addNode(Node parent, Node node)
1569    {
1570        return parent.appendChild(node);
1571    }
1572
1573    /**
1574     * Add a value to the specified node
1575     */
1576    public static Node addValue(Node node, String value)
1577    {
1578        final Node newNode;
1579        final String filteredValue = filterString(value);
1580
1581        if (node instanceof Document)
1582            newNode = ((Document) node).createTextNode(filteredValue);
1583        else
1584            newNode = node.getOwnerDocument().createTextNode(filteredValue);
1585
1586        if (newNode != null)
1587            node.appendChild(newNode);
1588
1589        return newNode;
1590    }
1591
1592    /**
1593     * Add a named element to the specified node
1594     */
1595    public static Element addElement(Node node, String name)
1596    {
1597        final Element element;
1598        final String filteredName = filterString(name);
1599
1600        if (node instanceof Document)
1601            element = ((Document) node).createElement(filteredName);
1602        else
1603            element = node.getOwnerDocument().createElement(filteredName);
1604
1605        node.appendChild(element);
1606
1607        return element;
1608    }
1609
1610    /**
1611     * Add a named element with a value to the specified node
1612     */
1613    public static Element addElement(Node node, String name, String value)
1614    {
1615        final Element element = addElement(node, name);
1616
1617        if (!StringUtil.isEmpty(value))
1618            addValue(element, value);
1619
1620        return element;
1621    }
1622
1623    /**
1624     * Add a generic element with specified type and name to the specified node
1625     */
1626    public static Element addGenericElement(Node node, String type, String name)
1627    {
1628        final Element element = addElement(node, type);
1629
1630        setGenericElementName(element, name);
1631
1632        return element;
1633    }
1634
1635    /**
1636     * Add a generic element with specified type, name and value to the specified node
1637     */
1638    public static Element addGenericElement(Node node, String type, String name, String value)
1639    {
1640        final Element element = addElement(node, type);
1641
1642        setGenericElementName(element, name);
1643        setGenericElementValue(element, value);
1644
1645        return element;
1646    }
1647
1648    /**
1649     * Set name of specified generic element
1650     */
1651    public static void setGenericElementName(Element element, String name)
1652    {
1653        if (element != null)
1654            element.setAttribute(ATTR_NAME_NAME, filterString(name));
1655    }
1656
1657    /**
1658     * Set value of specified generic element
1659     */
1660    public static void setGenericElementValue(Element element, String value)
1661    {
1662        if (element != null)
1663            element.setAttribute(ATTR_VALUE_NAME, filterString(value));
1664    }
1665
1666    /**
1667     * Set the specified node to the specified parent node.<br>
1668     * The new node replace the previous existing node with the same name.
1669     */
1670    public static Node setNode(Node parent, Node node)
1671    {
1672        final String name = node.getNodeName();
1673
1674        XMLUtil.removeNode(parent, name);
1675
1676        return XMLUtil.addNode(parent, node);
1677    }
1678
1679    /**
1680     * Set a element with specified name to specified node.<br>
1681     * If the Element was already existing then it's just returned.
1682     */
1683    public static Element setElement(Node node, String name)
1684    {
1685        // get element
1686        final Element element = getElement(node, name);
1687        if (element != null)
1688            return element;
1689
1690        return addElement(node, name);
1691    }
1692
1693    /**
1694     * Set a generic element with specified type and name to specified node.<br>
1695     * If the generic element was already existing then it's just returned.
1696     */
1697    public static Element setGenericElement(Node node, String type, String name)
1698    {
1699        // get generic element
1700        final Element element = getGenericElement(node, type, name);
1701        if (element != null)
1702            return element;
1703
1704        return addGenericElement(node, type, name);
1705    }
1706
1707    /**
1708     * Set an attribute and his value to the specified node
1709     */
1710    public static void setAttributeValue(Element element, String attribute, String value)
1711    {
1712        element.setAttribute(attribute, filterString(value));
1713    }
1714
1715    /**
1716     * Set an attribute and his value as boolean to the specified node
1717     */
1718    public static void setAttributeBooleanValue(Element element, String attribute, boolean value)
1719    {
1720        setAttributeValue(element, attribute, toString(value));
1721    }
1722
1723    /**
1724     * Set an attribute and his value as integer to the specified node
1725     */
1726    public static void setAttributeIntValue(Element element, String attribute, int value)
1727    {
1728        setAttributeValue(element, attribute, toString(value));
1729    }
1730
1731    /**
1732     * Set an attribute and his value as integer to the specified node
1733     */
1734    public static void setAttributeLongValue(Element element, String attribute, long value)
1735    {
1736        setAttributeValue(element, attribute, toString(value));
1737    }
1738
1739    /**
1740     * Set an attribute and his value as float to the specified node
1741     */
1742    public static void setAttributeFloatValue(Element element, String attribute, float value)
1743    {
1744        setAttributeValue(element, attribute, toString(value));
1745    }
1746
1747    /**
1748     * Set an attribute and his value as double to the specified node
1749     */
1750    public static void setAttributeDoubleValue(Element element, String attribute, double value)
1751    {
1752        setAttributeValue(element, attribute, toString(value));
1753    }
1754
1755    /**
1756     * Set an attribute and his value as byte array to the specified node
1757     */
1758    public static void setAttributeBytesValue(Element element, String attribute, byte[] value)
1759    {
1760        setAttributeValue(element, attribute, toString(value));
1761    }
1762
1763    /**
1764     * Set value to the specified element
1765     */
1766    public static void setValue(Element element, String value)
1767    {
1768        // remove child nodes
1769        removeAllChildren(element);
1770        // add value
1771        addValue(element, value);
1772    }
1773
1774    /**
1775     * Remove all characters that are valid XML markups.
1776     */
1777    public static String removeXMLMarkups(String s)
1778    {
1779        final StringBuffer out = new StringBuffer();
1780
1781        for (char c : s.toCharArray())
1782        {
1783            if ((c == '\'') || (c == '<') || (c == '>') || (c == '&') || (c == '\"'))
1784                continue;
1785
1786            out.append(c);
1787        }
1788
1789        return out.toString();
1790    }
1791
1792    /**
1793     * Remove any invalid XML character from the specified string.
1794     */
1795    public static String removeInvalidXMLCharacters(String text)
1796    {
1797        if (text == null)
1798            return "";
1799
1800        final String xml10pattern = "[^" + "\u0009\r\n" + "\u0020-\uD7FF" + "\uE000-\uFFFD"
1801                + "\ud800\udc00-\udbff\udfff" + "]";
1802        // final String xml11pattern = "[^" + "\u0001-\uD7FF" + "\uE000-\uFFFD" +
1803        // "\ud800\udc00-\udbff\udfff" + "]+";
1804
1805        // some OME generate incorrect "&#" sequence so we just replace them with "#"
1806        return text.replaceAll(xml10pattern, "").replaceAll("&#", "#");
1807    }
1808
1809    /**
1810     * Same as {@link #removeInvalidXMLCharacters(String)}
1811     */
1812    public static String filterString(String text)
1813    {
1814        return removeInvalidXMLCharacters(text);
1815    }
1816
1817    /**
1818     * Set value as boolean to the specified element
1819     */
1820    public static void setBooleanValue(Element element, boolean value)
1821    {
1822        setValue(element, toString(value));
1823    }
1824
1825    /**
1826     * Set value as integer to the specified element
1827     */
1828    public static void setIntValue(Element element, int value)
1829    {
1830        setValue(element, toString(value));
1831    }
1832
1833    /**
1834     * Set value as long to the specified element
1835     */
1836    public static void setLongValue(Element element, long value)
1837    {
1838        setValue(element, toString(value));
1839    }
1840
1841    /**
1842     * Set value as float to the specified element
1843     */
1844    public static void setFloatValue(Element element, float value)
1845    {
1846        setValue(element, toString(value));
1847    }
1848
1849    /**
1850     * Set value as double to the specified element
1851     */
1852    public static void setDoubleValue(Element element, double value)
1853    {
1854        setValue(element, toString(value));
1855    }
1856
1857    /**
1858     * Set value as byte array to the specified element
1859     */
1860    public static void setBytesValue(Element element, byte[] value)
1861    {
1862        setValue(element, toString(value));
1863    }
1864
1865    /**
1866     * Set an element with specified name and his value to the specified node
1867     */
1868    public static void setElementValue(Node node, String name, String value)
1869    {
1870        // get element (create it if needed)
1871        final Element element = setElement(node, name);
1872        // set value
1873        setValue(element, value);
1874    }
1875
1876    /**
1877     * Set an element with specified name and his value as boolean to the specified node
1878     */
1879    public static void setElementBooleanValue(Node node, String name, boolean value)
1880    {
1881        setElementValue(node, name, toString(value));
1882    }
1883
1884    /**
1885     * Set an element with specified name and his value as integer to the specified node
1886     */
1887    public static void setElementIntValue(Node node, String name, int value)
1888    {
1889        setElementValue(node, name, toString(value));
1890    }
1891
1892    /**
1893     * Set an element with specified name and his value as long to the specified node
1894     */
1895    public static void setElementLongValue(Node node, String name, long value)
1896    {
1897        setElementValue(node, name, toString(value));
1898    }
1899
1900    /**
1901     * Set an element with specified name and his value as float to the specified node
1902     */
1903    public static void setElementFloatValue(Node node, String name, float value)
1904    {
1905        setElementValue(node, name, toString(value));
1906    }
1907
1908    /**
1909     * Set an element with specified name and his value as double to the specified node
1910     */
1911    public static void setElementDoubleValue(Node node, String name, double value)
1912    {
1913        setElementValue(node, name, toString(value));
1914    }
1915
1916    /**
1917     * Set an element with specified name and his value as byte array to the specified node
1918     */
1919    public static void setElementBytesValue(Node node, String name, byte[] value)
1920    {
1921        setElementValue(node, name, toString(value));
1922    }
1923
1924    /**
1925     * Set a generic element with specified type and name and his value to the specified node
1926     */
1927    public static void setGenericElementValue(Node node, String type, String name, String value)
1928    {
1929        // get generic element (create it if needed)
1930        final Element element = setGenericElement(node, type, name);
1931
1932        if (element != null)
1933            element.setAttribute(ATTR_VALUE_NAME, value);
1934    }
1935
1936    /**
1937     * Set an element with specified type and name and his value as boolean to the specified node
1938     */
1939    public static void setGenericElementBooleanValue(Node node, String type, String name, boolean value)
1940    {
1941        setGenericElementValue(node, type, name, toString(value));
1942    }
1943
1944    /**
1945     * Set an element with specified type and name and his value as integer to the specified node
1946     */
1947    public static void setGenericElementIntValue(Node node, String type, String name, int value)
1948    {
1949        setGenericElementValue(node, type, name, toString(value));
1950    }
1951
1952    /**
1953     * Set an element with specified type and name and his value as long to the specified node
1954     */
1955    public static void setGenericElementLongValue(Node node, String type, String name, long value)
1956    {
1957        setGenericElementValue(node, type, name, toString(value));
1958    }
1959
1960    /**
1961     * Set an element with specified type and name and his value as float to the specified node
1962     */
1963    public static void setGenericElementFloatValue(Node node, String type, String name, float value)
1964    {
1965        setGenericElementValue(node, type, name, toString(value));
1966    }
1967
1968    /**
1969     * Set an element with specified type and name and his value as double to the specified node
1970     */
1971    public static void setGenericElementDoubleValue(Node node, String type, String name, double value)
1972    {
1973        setGenericElementValue(node, type, name, toString(value));
1974    }
1975
1976    /**
1977     * Set an element with specified type and name and his value as byte array to the specified node
1978     */
1979    public static void setGenericElementBytesValue(Node node, String type, String name, byte[] value)
1980    {
1981        setGenericElementValue(node, type, name, toString(value));
1982    }
1983
1984    /**
1985     * Remove a node with specified name from the specified node
1986     */
1987    public static boolean removeNode(Node node, String name)
1988    {
1989        final Node subNode = getSubNode(node, name);
1990
1991        if (subNode != null)
1992            return removeNode(node, subNode);
1993
1994        return false;
1995    }
1996
1997    /**
1998     * Remove the specified node from the specified parent node
1999     */
2000    public static boolean removeNode(Node parent, Node child)
2001    {
2002        int tries = 3;
2003        // RuntimeException exception = null;
2004
2005        // have to make several attempts as sometime XML library fails to correctly retrieve XML data
2006        while (tries > 0)
2007        {
2008            try
2009            {
2010                parent.removeChild(child);
2011                return true;
2012            }
2013            catch (RuntimeException e)
2014            {
2015                // exception = e;
2016                tries--;
2017            }
2018        }
2019
2020        // we just ignore here
2021        return false;
2022    }
2023
2024    /**
2025     * @deprecated Use {@link #removeAllChildren(Node)} instead
2026     */
2027    @Deprecated
2028    public static void removeAllChilds(Node node)
2029    {
2030        removeAllChildren(node);
2031    }
2032
2033    /**
2034     * Remove all children from the specified node
2035     */
2036    public static void removeAllChildren(Node node)
2037    {
2038        while (node.hasChildNodes())
2039            node.removeChild(node.getLastChild());
2040    }
2041
2042    /**
2043     * @deprecated Use {@link #removeChildren(Node, String)} instead
2044     */
2045    @Deprecated
2046    public static void removeChilds(Node node, String name)
2047    {
2048        removeChildren(node, name);
2049    }
2050
2051    /**
2052     * Remove all children with specified name from the specified node
2053     */
2054    public static void removeChildren(Node node, String name)
2055    {
2056        Node currentChild = node.getFirstChild();
2057
2058        while (currentChild != null)
2059        {
2060            final Node nextChild = currentChild.getNextSibling();
2061
2062            if (currentChild.getNodeName().equals(name))
2063                node.removeChild(currentChild);
2064
2065            currentChild = nextChild;
2066        }
2067    }
2068
2069    /**
2070     * Remove an attribute from the specified element
2071     */
2072    public static void removeAttribute(Element element, String name)
2073    {
2074        element.removeAttribute(name);
2075    }
2076
2077    /**
2078     * Remove all attribute from the specified element
2079     */
2080    public static void removeAllAttributes(Element element)
2081    {
2082        final NamedNodeMap nodeMap = element.getAttributes();
2083
2084        for (int i = 0; i < nodeMap.getLength(); i++)
2085            element.removeAttribute(nodeMap.item(i).getNodeName());
2086    }
2087}