#!/usr/bin/env rexx /* create an instance of the JAXP DocumentBuilderFactory */ factory=bsf.loadClass("javax.xml.parsers.DocumentBuilderFactory")~newInstance /* make sure that parser is set to be namespace aware */ factory~setNamespaceAware(.true) /* now create the DocumentBuilder object */ parser=factory~newDocumentBuilder /* create a Rexx object for error handling */ eh=.errorHandler~new /* create a Java proxy using the Rexx object for error handling */ javaProxy=BsfCreateRexxProxy(eh, , "org.xml.sax.ErrorHandler") /* set the parser's error handler */ parser~setErrorHandler(javaProxy) /* parse the file, result is full DOM-tree */ document=parser~parse("https://www.w3schools.com/xml/books.xml") /* get constant value to determine node types to filter */ .local~show_element=bsf.getConstant("org.w3c.dom.traversal.NodeFilter", "SHOW_ELEMENT") whatToShow=.show_element /* create a TreeWalker with only Element nodes */ walker=document~createTreeWalker(document, whatToShow, .nil, .true) /* process list of Element nodes */ jTreeRoot=walkTheTree( walker~firstChild, .nil ) /* now prepare and display JTree */ tree =.bsf~new("javax.swing.JTree", jTreeRoot) treeView=.bsf~new("javax.swing.JScrollPane", tree) .bsf~bsf.import("javax.swing.JFrame", "JFrame") /* import the Java class */ f =.JFrame~new("XML Tree") /* create an instance */ f~setDefaultCloseOperation(.JFrame~EXIT_ON_CLOSE) /* get constant */ f~getContentPane~add(treeView) wl=.windowListener~new /* create a Rexx WindowListener object */ f~addWindowListener(BsfCreateRexxProxy(wl,,"java.awt.event.WindowListener")) f~~pack~~show~~toFront /* pack, show and move JFrame to front */ loop forever /* wait until JFrame got closed */ if wl~isClosing=.true then leave call sysSleep .01 /* sleep a while to save cycles */ end ::requires BSF.CLS /* get the Java support */ ::routine walkTheTree /* walks the tree recursively */ use arg node, jTreeParentNode data=ppAtts(node~getNodeName, node~getAttributes) /* define text for tree node */ newJTreeNode=.bsf~new("javax.swing.tree.DefaultMutableTreeNode", data) /* create new node */ if jTreeParentNode=.nil then /* save root */ jTreeParentNode=newJTreeNode else /* insert into tree */ jTreeParentNode~insert(newJTreeNode, jTreeParentNode~getChildCount) child=node~firstChild /* depth first */ do while child<>.nil if child~getNodeType=.show_element then /* child could be of different type!*/ call walkTheTree child, newJTreeNode /* recurse, i.e. one level deeper */ child=child~nextSibling /* breadth next */ end return jTreeParentNode ::routine ppAtts /* pretty prints element name with attributes, if any; shows attribute typename */ use arg strElementName, atts tmpStr=strElementName tmpStr2="" if atts~getLength>0 then /* o.k. attributes defined for this element */ do do i=0 to atts~getLength-1 /* iterate over all attributes, 0-based */ att=atts~item(i) /* get attribute node */ /* DOM 2.0 is not making attribute types available, hence no type information */ tmpStr2=tmpStr2 att~getName'="'att~getValue'"' end end return pp((tmpStr tmpStr2~strip)~strip) ::class ErrorHandler /* will handle "org.xml.sax.ErrorHandler" events*/ ::method unknown /* handles "warning", "error" and "fatalError" events */ use arg methName, argArray /* fetch arguments */ exception=argArray[1] /* retrieve SAXException argument */ /* display error message */ .error~say(methName":" "line="exception~getLineNumber",col="exception~getColumnNumber":" pp(exception~getMessage)) ::class windowListener /* a Rexx implemented WindowListener */ ::method init /* constructor, setting attribute to a defined value */ expose isClosing isClosing=.false ::method isClosing attribute ::method windowClosing /* if windowClosing event occurred, indicate it */ expose isClosing isClosing=.true ::method unknown /* intercept all other messages to do nothing */