This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 136595
Collapse All | Expand All

(-)a/openide.util/apichanges.xml (+16 lines)
Lines 1457-1462 Link Here
1457
      <class package="org.openide.xml" name="XMLUtil"/>
1457
      <class package="org.openide.xml" name="XMLUtil"/>
1458
      <issue number="16629"/>
1458
      <issue number="16629"/>
1459
    </change>
1459
    </change>
1460
    <change id="refactored-methods-into-XMLUtil">
1461
        <api name="xml"/>
1462
        <summary>Refactored XML methods from various modules to be added
1463
        to <code>XMLUtil</code>.  Six new methods added.</summary>
1464
        <version major="8" minor="3"/>
1465
        <date day="15" month="3" year="2010"/>
1466
        <author login="mvfranz"/>
1467
        <compatibility addition="yes"/>
1468
        <description>
1469
            <p>
1470
                Refactored XML related methods into XMLUtil.
1471
            </p>
1472
        </description>
1473
        <class package="org.openide.xml" name="XMLUtil"/>
1474
        <issue number="136595"/>
1475
    </change>
1460
</changes>
1476
</changes>
1461
<htmlcontents>
1477
<htmlcontents>
1462
<head>
1478
<head>
(-)a/openide.util/manifest.mf (-1 / +1 lines)
Lines 1-5 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.util
2
OpenIDE-Module: org.openide.util
3
OpenIDE-Module-Localizing-Bundle: org/openide/util/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openide/util/Bundle.properties
4
OpenIDE-Module-Specification-Version: 8.2
4
OpenIDE-Module-Specification-Version: 8.3
5
5
(-)a/openide.util/src/org/openide/xml/XMLUtil.java (+212 lines)
Lines 45-52 Link Here
45
import java.io.IOException;
45
import java.io.IOException;
46
import java.io.OutputStream;
46
import java.io.OutputStream;
47
import java.io.StringReader;
47
import java.io.StringReader;
48
import java.util.ArrayList;
49
import java.util.Arrays;
48
import java.util.HashMap;
50
import java.util.HashMap;
49
import java.util.HashSet;
51
import java.util.HashSet;
52
import java.util.List;
50
import java.util.Map;
53
import java.util.Map;
51
import java.util.Set;
54
import java.util.Set;
52
import javax.xml.parsers.DocumentBuilder;
55
import javax.xml.parsers.DocumentBuilder;
Lines 842-845 Link Here
842
        }
845
        }
843
        return doc;
846
        return doc;
844
    }
847
    }
848
849
    /**
850
     * Append a child element to the parent at the specified location.
851
     *
852
     * <ul>The parent document must be
853
     * <li>a valid document</li>
854
     * <li>order must contain all direct children</li>
855
     * </ul>
856
     *
857
     *
858
     * The implementation is 'insert before', and since the order of existing elements
859
     * is not validated, it is important to place the new child <em>before</em>
860
     * the existing item instead of after the existing item.
861
     *
862
     * @param parent parent to which the child will be appended
863
     * @param el element to be added
864
     * @param order order of the elements which must be followed
865
     * @throws IllegalArgumentException if the order cannot be followed, either
866
     * a missing existing child or missing new child entry from the desiredAppendOrder
867
     *
868
     * @since 8.3
869
     */
870
    public static void appendChildElement(Element parent, Element el, String[] order) throws IllegalArgumentException {
871
        List l = Arrays.asList(order);
872
        int index = l.indexOf(el.getLocalName());
873
874
        // ensure the new new element is contained in the 'order'
875
        if (index == -1) {
876
            throw new IllegalArgumentException("new child element '"+ el.getLocalName() + "' not specified in order " + l); // NOI18N
877
        }
878
879
        List<Element> elements = findSubElements(parent);
880
        Element insertBefore = null;
881
882
        for (Element e : elements) {
883
            int index2 = l.indexOf(e.getLocalName());
884
            // ensure that all existing elements are in 'order'
885
            if (index2 == -1) {
886
                throw new IllegalArgumentException("Existing child element '" + e.getLocalName() + "' not specified in order " + l);  // NOI18N
887
            }
888
            if (index2 > index) {
889
                insertBefore = e;
890
                break;
891
            }
892
        }
893
894
        parent.insertBefore(el, insertBefore);
895
    }
896
897
    /**
898
     * Find all direct child elements of an element.
899
     * Children which are all-whitespace text nodes or comments are ignored; others cause
900
     * an exception to be thrown.
901
     * @param parent a parent element in a DOM tree
902
     * @return a list of direct child elements (may be empty)
903
     * @throws IllegalArgumentException if there are non-element children besides whitespace
904
     * 
905
     * @since 8.3
906
     */
907
    public static List<Element> findSubElements(Element parent) throws IllegalArgumentException {
908
        NodeList l = parent.getChildNodes();
909
        List<Element> elements = new ArrayList<Element>(l.getLength());
910
        for (int i = 0; i < l.getLength(); i++) {
911
            Node n = l.item(i);
912
            if (n.getNodeType() == Node.ELEMENT_NODE) {
913
                elements.add((Element) n);
914
            } else if (n.getNodeType() == Node.TEXT_NODE) {
915
                String text = ((Text) n).getNodeValue();
916
                if (text.trim().length() > 0) {
917
                    throw new IllegalArgumentException("non-ws text encountered in " + parent + ": " + text); // NOI18N
918
                }
919
            } else if (n.getNodeType() == Node.COMMENT_NODE) {
920
                // OK, ignore
921
            } else {
922
                throw new IllegalArgumentException("unexpected non-element child of " + parent + ": " + n); // NOI18N
923
            }
924
        }
925
        return elements;
926
    }
927
928
    /**
929
     * Search for an XML element in the direct children of parent only.
930
     *
931
     * This compares localName (uses nodeName is localName is null) to name,
932
     * and checks the tags namespace with the provided namespace.
933
     * A <code>null</code> namespace will match any namespace.
934
     *
935
     * <ul>This is differs from the DOM version by:
936
     * <li>not searching recursively</li>
937
     * <li>returns a single result</li>
938
     * </ul>
939
     *
940
     * @param parent a parent element
941
     * @param name the intended local name
942
     * @param namespace the intended namespace (or null)
943
     * @return the one child element with that name, or null if none
944
     * @throws IllegalArgumentException if there is multiple elements of the same name
945
     * 
946
     * @since 8.3
947
     */
948
    public static Element findElement(Element parent, String name, String namespace) throws IllegalArgumentException {
949
        Element result = null;
950
        NodeList l = parent.getChildNodes();
951
        int nodeCount = l.getLength();
952
        for (int i = 0; i < nodeCount; i++) {
953
            if (l.item(i).getNodeType() == Node.ELEMENT_NODE) {
954
                Node node = l.item(i);
955
                String localName = node.getLocalName();
956
                localName = localName == null ? node.getNodeName() : localName;
957
                
958
                if (name.equals(localName)
959
			&& (namespace == null || namespace.equals(node.getNamespaceURI()))) {
960
                    if (result == null) {
961
                        result = (Element)node;
962
                    } else {
963
                        throw new IllegalArgumentException("more than one element with same name found");
964
                    }
965
                }
966
            }
967
        }
968
        return result;
969
    }
970
971
    /**
972
     * Extract nested text from a node.
973
     * Currently does not handle coalescing text nodes, CDATA sections, etc.
974
     * @param parent a parent element
975
     * @return the nested text, or null if none was found
976
     * 
977
     * @since 8.3
978
     */
979
    public static String findText(Node parent) {
980
        NodeList l = parent.getChildNodes();
981
        for (int i = 0; i < l.getLength(); i++) {
982
            if (l.item(i).getNodeType() == Node.TEXT_NODE) {
983
                Text text = (Text) l.item(i);
984
                return text.getNodeValue();
985
            }
986
        }
987
        return null;
988
    }
989
990
    /**
991
     * Convert an XML fragment from one namespace to another.
992
     * 
993
     * @param from
994
     * @param namespace
995
     * @return
996
     * 
997
     * @since 8.3
998
     */
999
    public static Element translateXML(Element from, String namespace) {
1000
        Element to = from.getOwnerDocument().createElementNS(namespace, from.getLocalName());
1001
        NodeList nl = from.getChildNodes();
1002
        int length = nl.getLength();
1003
        for (int i = 0; i < length; i++) {
1004
            Node node = nl.item(i);
1005
            Node newNode;
1006
            if (node.getNodeType() == Node.ELEMENT_NODE) {
1007
                newNode = translateXML((Element) node, namespace);
1008
            } else {
1009
                newNode = node.cloneNode(true);
1010
            }
1011
            to.appendChild(newNode);
1012
        }
1013
        NamedNodeMap m = from.getAttributes();
1014
        for (int i = 0; i < m.getLength(); i++) {
1015
            Node attr = m.item(i);
1016
            to.setAttribute(attr.getNodeName(), attr.getNodeValue());
1017
        }
1018
        return to;
1019
    }
1020
1021
    /**
1022
     * Copy elements from one document to another attaching at the specified element
1023
     * and translating the namespace.
1024
     *
1025
     * @param from copy the children of this element (exclusive)
1026
     * @param to where to attach the copied elements
1027
     * @param newNamespace destination namespace
1028
     * 
1029
     * @since 8.3
1030
     */
1031
    public static void copyDocument(Element from, Element to, String newNamespace) {
1032
        Document doc = to.getOwnerDocument();
1033
        NodeList nl = from.getChildNodes();
1034
        int length = nl.getLength();
1035
        for (int i = 0; i < length; i++) {
1036
            Node node = nl.item(i);
1037
            Node newNode = null;
1038
            if (Node.ELEMENT_NODE == node.getNodeType()) {
1039
                Element oldElement = (Element) node;
1040
                newNode = doc.createElementNS(newNamespace, oldElement.getTagName());
1041
                NamedNodeMap m = oldElement.getAttributes();
1042
                Element newElement = (Element) newNode;
1043
                for (int index = 0; index < m.getLength(); index++) {
1044
                    Node attr = m.item(index);
1045
                    newElement.setAttribute(attr.getNodeName(), attr.getNodeValue());
1046
                }
1047
                copyDocument(oldElement, newElement, newNamespace);
1048
            } else {
1049
                newNode = node.cloneNode(true);
1050
                newNode = to.getOwnerDocument().importNode(newNode, true);
1051
            }
1052
            if (newNode != null) {
1053
                to.appendChild(newNode);
1054
            }
1055
        }
1056
    }
845
}
1057
}
(-)a/openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java (+207 lines)
Lines 49-54 Link Here
49
import java.io.StringReader;
49
import java.io.StringReader;
50
import java.lang.ref.Reference;
50
import java.lang.ref.Reference;
51
import java.lang.ref.WeakReference;
51
import java.lang.ref.WeakReference;
52
import java.util.List;
52
import javax.xml.XMLConstants;
53
import javax.xml.XMLConstants;
53
import javax.xml.parsers.DocumentBuilderFactory;
54
import javax.xml.parsers.DocumentBuilderFactory;
54
import javax.xml.transform.stream.StreamSource;
55
import javax.xml.transform.stream.StreamSource;
Lines 497-500 Link Here
497
        assertGC("can collect resolver", resolverRef);
498
        assertGC("can collect resolver", resolverRef);
498
    }
499
    }
499
500
501
    public void testAppendChildElement() throws Exception {
502
        Document doc = XMLUtil.parse(new InputSource(new StringReader("<root></root>")), false, true, null, null);
503
        Element parent = doc.createElementNS("unittest", "parent");
504
        Element newElement1 = doc.createElementNS("unittest", "new_element1");
505
        Element newElement2 = doc.createElementNS("unittest", "new_element2");
506
        Element newElement3 = doc.createElementNS("unittest", "new_element3");
507
508
        // append to the default root node (no match in order)
509
        XMLUtil.appendChildElement(parent, newElement1, new String[] { "new_element2", "new_element1" });
510
        NodeList children = parent.getChildNodes();
511
        assertEquals(1, children.getLength());
512
513
        // append after the child we just appended
514
        XMLUtil.appendChildElement(parent, newElement2, new String[] { "new_element2", "new_element1" });
515
516
        children = parent.getChildNodes();
517
        assertEquals(2, children.getLength());
518
        Node firstChild = parent.getChildNodes().item(0);
519
        Node secondChild = parent.getChildNodes().item(1);
520
        assertEquals("new_element2", firstChild.getNodeName());
521
        assertEquals("new_element1", secondChild.getNodeName());
522
523
        // failures
524
525
        try {
526
            // new child is not in the order list
527
            XMLUtil.appendChildElement(parent, newElement3, new String[] { "new_element2", "new_element1"});
528
            fail("Expecting IAE");
529
        } catch (IllegalArgumentException e) {
530
            assertEquals("new child element 'new_element3' not specified in order [new_element2, new_element1]", e.getMessage());
531
        }
532
        try {
533
            // existing child not in the order list
534
            XMLUtil.appendChildElement(parent, newElement3, new String[] { "new_element3"});
535
            fail("Expecting IAE");
536
        } catch (IllegalArgumentException e) {
537
            assertEquals("Existing child element 'new_element2' not specified in order [new_element3]", e.getMessage());
538
        }
539
    }
540
541
    public void testFindSubElements() throws Exception {
542
        Document doc = XMLUtil.parse(new InputSource(new StringReader("<root> <child1></child1><child2/><!-- comment --><child3/></root>")),
543
                false, true, null, null);
544
545
        Element parent = doc.getDocumentElement();
546
        assertEquals(5, parent.getChildNodes().getLength());
547
        List<Element> subElements = XMLUtil.findSubElements(parent);
548
        assertEquals(3, subElements.size());
549
        Element firstChild = subElements.get(0);
550
        Element secondChild = subElements.get(1);
551
        Element thirdChild = subElements.get(2);
552
553
        assertEquals("child1", firstChild.getNodeName());
554
        assertEquals("child2", secondChild.getNodeName());
555
        assertEquals("child3", thirdChild.getNodeName());
556
557
        Document failureDoc = XMLUtil.parse(new InputSource(new StringReader("<root>Non whitespace<!-- comment --></root>")),
558
            false, true, null, null);
559
        Element failedParent = failureDoc.getDocumentElement();
560
        try {
561
            XMLUtil.findSubElements(failedParent);
562
            fail("expected IAE");
563
        } catch (IllegalArgumentException e) { }
564
    }
565
566
    public void testFindElement() throws Exception {
567
        String xmlDoc = "<root> " +
568
                        " <h:table xmlns:h=\"http://www.w3.org/TR/html4/\">" +
569
                        " </h:table>" +
570
                        " <f:table xmlns:f=\"http://www.w3schools.com/furniture\">" +
571
                        " </f:table>" +
572
                        " <dup/><dup/>" +
573
                        " <h:form xmlns:h=\"http://www.w3.org/TR/html4/\">" +
574
                        " </h:form>" +
575
                        "</root>";
576
        
577
        Document doc = XMLUtil.parse(new InputSource(new StringReader(xmlDoc)), false, true, null, null);
578
        Element parent = doc.getDocumentElement();
579
580
        Element doesNotExist1 = XMLUtil.findElement(parent, "doesNotExist", "h");
581
        assertNull(doesNotExist1);
582
583
        Element doesNotExist2 = XMLUtil.findElement(parent, "doesNotExist", null);
584
        assertNull(doesNotExist2);
585
586
        Element noTable2 = XMLUtil.findElement(parent, "table", "h");
587
        assertNull(noTable2);
588
589
        Element noTable3 = XMLUtil.findElement(parent, "table", "f");
590
        assertNull(noTable3);
591
592
        Element table1 = XMLUtil.findElement(parent, "table", "http://www.w3.org/TR/html4/");
593
        assertNotNull(table1);
594
595
        Element table2 = XMLUtil.findElement(parent, "table", "http://www.w3schools.com/furniture");
596
        assertNotNull(table2);
597
598
        Element form1 = XMLUtil.findElement(parent, "form", "http://www.w3.org/TR/html4/");
599
        assertNotNull(form1);
600
601
        Element form2 = XMLUtil.findElement(parent, "form", null);
602
        assertNotNull(form2);
603
604
        assertEquals(form1, form2);
605
606
        try {
607
            XMLUtil.findElement(parent, "dup", null);
608
            fail("Expected IAE");
609
        } catch (IllegalArgumentException e) { }
610
611
        try {
612
            XMLUtil.findElement(parent, "table", null);
613
            fail("Expected IAE");
614
        } catch (IllegalArgumentException e) { }
615
    }
616
617
    public void testFindText() throws Exception {
618
        Document doc = XMLUtil.parse(new InputSource(new StringReader("<root>Text To Find<child></child></root>")),
619
                false, true, null, null);
620
621
        Element parent = doc.getDocumentElement();
622
        String foundText = XMLUtil.findText(parent);
623
624
        assertEquals("Text To Find", foundText);
625
626
        String notFoundText = XMLUtil.findText(parent.getFirstChild());
627
628
        assertNull(notFoundText);
629
    }
630
631
    public void testTranslateXML() throws Exception {
632
        // don't add any whitespace to the first 3 nodes
633
        String xmlDoc = "<root><table bgcolor='red'><tr>" +
634
                        "   <td>Apples</td>" +
635
                        "   <td>Bananas</td>" +
636
                        "  </tr>" +
637
                        " </table>" +
638
                        " <!-- comment -->" +
639
                        "<![CDATA[free form data]]>" +
640
                        "</root>";
641
642
        Document doc = XMLUtil.parse(new InputSource(new StringReader(xmlDoc)), false, true, null, null);
643
        Element parent = doc.getDocumentElement();
644
645
        Element translated = XMLUtil.translateXML((Element) parent.getFirstChild(), "http://www.w3.org/TR/html4/");
646
647
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
648
        XMLUtil.write(doc, baos, "UTF-8");
649
650
        Document destDoc = XMLUtil.parse(new InputSource(new StringReader("<root/>")), false, true, null, null);
651
652
        destDoc.importNode(translated, true);
653
        baos = new ByteArrayOutputStream();
654
        XMLUtil.write(destDoc, baos, "UTF-8");
655
656
        assertEquals("http://www.w3.org/TR/html4/", translated.getNamespaceURI());
657
        assertEquals(1, translated.getAttributes().getLength());
658
659
        assertEquals("http://www.w3.org/TR/html4/", translated.getFirstChild().getNamespaceURI());
660
        assertEquals(0, translated.getFirstChild().getAttributes().getLength());
661
    }
662
663
    public void testCopyDocument() throws Exception {
664
        String srcXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
665
                        "<root>" +
666
                        "   <table bgcolor='red'>" +
667
                        "    <tr>" +
668
                        "           <td>Apples</td>" +
669
                        "           <td>Bananas</td>" +
670
                        "       </tr>" +
671
                        "   </table>" +
672
                        " <!-- comment -->" +
673
                        "</root>";
674
675
        String resultXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
676
                        "<root>\n" +
677
                        "    <table xmlns=\"http://www.w3.org/TR/html4/\" bgcolor=\"red\">\n" +
678
                        "        <tr>\n" +
679
                        "            <td>Apples</td>\n" +
680
                        "            <td>Bananas</td>\n" +
681
                        "        </tr>\n" +
682
                        "    </table>\n" +
683
                        "    <!-- comment -->\n" +
684
                        "</root>\n";
685
686
        Document srcDoc = XMLUtil.parse(new InputSource(new StringReader(srcXml)), false, true, null, null);
687
        Element srcRoot = srcDoc.getDocumentElement();
688
689
        Document dstDoc = XMLUtil.parse(new InputSource(new StringReader("<root/>")), false, true, null, null);
690
691
        Element dstRoot = dstDoc.getDocumentElement();
692
        XMLUtil.copyDocument(srcRoot, dstRoot, "http://www.w3.org/TR/html4/");
693
694
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
695
        XMLUtil.write(dstDoc, baos, "UTF-8");
696
        assertEquals(resultXml, baos.toString());
697
698
        assertEquals(1, dstDoc.getChildNodes().getLength());
699
        Element root = dstDoc.getDocumentElement();
700
        Element tableNode = (Element) root.getFirstChild().getNextSibling();
701
702
        assertEquals("table", tableNode.getNodeName());
703
        assertEquals("http://www.w3.org/TR/html4/", tableNode.getNamespaceURI());
704
        assertEquals(1, tableNode.getAttributes().getLength());
705
    }
706
500
}
707
}

Return to bug 136595