PBToolboxAI v5 ← Site

xmltree — u_pbt_xmltree #

← Component reference · Guide contents

xmltree shows a XML value as a collapsible tree, colour-coded: a config screen, an API response, an integration debug. You set the XML text in is_xml, the component shows it; a click on a node reports its path (ue_node_clicked), invalid XML raises ue_error. It changes nothing: it is a VIEWER.

▶ See it live — Demo application, XML tree tile, with the code and this page side by side.


At a glance #

Userobjectu_pbt_xmltree
InputThe XML text, in is_xml (a string)
Fold / unfoldEach element by its + / − marker in the line-number gutter, by its path (of_expand_path, of_collapse_path), or all at once (of_expand_all, of_collapse_all)
FeedbackA click on a node gives its path (ue_node_clicked), an XPath n_pbt_xml reads as it is: /order/lines/line[2], /order/@id for an attribute, /order/comment()[1] for a comment — every line has its own; invalid XML raises ue_error and shows the source, the faulty line marked
FidelityEvery node in its place, in document order: text between two children, CDATA sections, comments, processing instructions, the XML declaration

Quick start #

// Show an XML response as a tree
uo_xml.is_xml = inv_rest.of_response_text()

// Fold everything, then let the user open what interests them
uo_xml.of_collapse_all()

// ue_node_clicked : the path of the node clicked, an XPath ("/order/lines/line[2]",
// "/order/@id" for an attribute) -> n_pbt_xml.of_get_value(as_path) reads its value

Properties #

PropertyTypeDefaultDescription
is_xmlstring""The XML text to show, read and displayed as a tree: every node in its place. Empty clears the tree, without an error; invalid XML raises ue_error and shows the source around the faulty line. Reads back exactly as it was set, an invalid text included. A new document starts with nothing selected and every element open: of_get_layout before and of_set_layout after keep what the user opened
ib_wrapbooleantrueLong lines wrap (true, the default) or stay on one line with a horizontal scrollbar (false) — a code-editor feel
ib_search_enabledbooleantrueCtrl+F in the tree opens a search box — the same search as of_search: type to highlight, Enter or F3 next, Shift+Enter or Shift+F3 previous, Escape closes. false leaves the shortcut to an application that searches from its own box. The box carries three toggles before the counter, Aa (ib_find_match_case), ab (ib_find_whole_word) and & (ib_find_decoded); changing an option restarts the current search from its first occurrence
ib_find_match_casebooleanfalseSearch option: finds only the text with the same case. The Aa toggle of the search box (Ctrl+F) is the same switch; applies to of_search and to what the user types. Read live; of_reset puts it back to false
ib_find_whole_wordbooleanfalseSearch option: finds the text only as a whole word (a letter, a digit or a _ next to it belongs to the word: id is found neither inside user_id nor inside ids). The ab toggle of the search box is the same switch. Read live; of_reset puts it back to false
ib_find_decodedbooleanfalseSearch option: searches the decoded VALUES — a text and an attribute value read as n_pbt_xml reads them (Durand & Co finds Durand &amp; Co, x < y finds x &lt; y); the highlight covers the whole escape. false searches the text as it is shown. The & toggle of the search box is the same switch. Read live; of_reset puts it back to false
is_theme_stylestring""Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change
is_theme_modestring""Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change
il_theme_accentlong-1Accent colour of this component (-1 = the application accent, or the theme's)
is_tooltipstring""Simple tooltip shown when hovering the component
is_super_tooltip_titlestring""Title of the rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Text of the rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the rich tooltip

Methods #

MethodDescription
of_expand_all ( ) → longUnfolds every element. No ue_node_toggled: no gesture opens the whole tree at once. Returns 0, -2 when the component is not created
of_collapse_all ( ) → longFolds every nested element (the root stays visible). A selection hidden by a fold moves onto the folded element, and ue_selection_changed says so. No ue_node_toggled: no gesture folds the whole tree at once. Returns 0, -2 when the component is not created
of_clear ( ) → longEmpties the tree (like is_xml = ""); ib_wrap, ib_search_enabled, ib_find_match_case and ib_find_whole_word keep their values (of_reset is the one that puts every property back). Returns 0, -2 when the component is not created
of_expand_to_level ( long al_level ) → longShows the tree down to al_level: elements at that depth or deeper fold shut (1 = the root's direct children, 0 folds the root). No ue_node_toggled; a selection it moves onto a folded element raises ue_selection_changed. Returns 0, -2 when the component is not created
of_expand_path ( string as_path ) → longOpens ONE element by its path — any XPath, like of_select_path — and the elements above it so it can be seen. Like its + marker, it raises ue_node_toggled for the element and for each folded element above it opened on the way (nothing for an element already open). Returns 0, -5 if no element with children matches, -2 if the component is not created
of_collapse_path ( string as_path ) → longFolds ONE element by its path (any XPath). Like its − marker, it raises ue_node_toggled when the element was open, and ue_selection_changed when the selection has to move onto it. Returns 0, -5 if no element with children matches, -2 if the component is not created
of_is_expanded ( string as_path ) → booleantrue when the element at that path (any XPath) is open, read LIVE; false when it is folded, and for a node without children or a path that matches nothing. Enough to save what the user opened and restore it
of_get_layout ( ) → stringThe layout of the tree, read LIVE, as a JSON text to store: the folded elements (collapsed, or expanded when that list is shorter — every element it does not name is then folded), the selected path (selected, null with no selection) and the line at the top of the view (top, a path, never pixels). Give it back to of_set_layout, after a new document too
of_set_layout ( string as_layout_json ) → longGives the tree back a layout of_get_layout gave: the folds (a path the document no longer has is ignored, a new element keeps its default), the selection (ue_selection_changed, as of_select_path) and the line at the top. ue_layout_changed follows once when the folds changed. Returns 0, -5 if the text is not a JSON object, -2 if the component is not created
of_search ( string as_query ) → longHighlights every occurrence (case-insensitive by default — see ib_find_match_case —, whole words only with ib_find_whole_word) and jumps to the first; only the elements that hide the CURRENT occurrence open, and of_clear_search folds them back. ue_search_result says how many. The search looks in the text as it is SHOWN: in a text, Durand & Co is written Durand &amp; Co and is searched so (a CDATA section shows it as it is) — with ib_find_decoded, in the decoded values, where Durand & Co finds both. An empty query is of_clear_search; a search ends an of_find_xpath. The search box opens with the query in it and the focus on it (the same as Ctrl+F): Enter moves to the next; with ib_search_enabled at false, the tree only highlights. Returns 0, or a negative code
of_search_next ( ) → longMoves to the NEXT match (wraps to the first after the last); during an of_find_xpath, to the next node, which is selected. ue_search_result reports the new position. Returns 0, or a negative code
of_search_prev ( ) → longMoves to the PREVIOUS match (wraps to the last before the first); during an of_find_xpath, to the previous node, which is selected. ue_search_result reports the new position. Returns 0, or a negative code
of_clear_search ( ) → longClears the search, or the of_find_xpath: no more highlight nor current match (of_match_count returns 0), the search box empties and closes, and the elements the search opened fold back as they were before it. Returns 0, or a negative code
of_find_xpath ( string as_xpath ) → longHighlights EVERY node of the tree an XPath matches (//line, //line[@qty > 1], //@sku) and selects the first; of_search_next / of_search_prev (and F3) walk them, each one selected, and ue_search_result counts them. A text search, of_clear_search, Ctrl+F or a new document ends it. Returns the number of nodes found (0 when none), -5 if the text is not an XPath of nodes (a syntax error, a number such as count(…), an unknown prefix), -2 if the component is not created. An empty text is of_clear_search
of_select_path ( string as_path ) → longSelects and scrolls to the node at as_path; like the keyboard, it raises ue_selection_changed (nothing when the node is already selected); the folded elements that hide it open. as_path is ANY XPath 1.0 that designates a node of the tree: a path as the tree gives it (/order/@id), //line[@sku='A'], /order/lines/line[1], another prefix bound to the same namespace; the first node it matches that the tree SHOWS is selected (a blank of layout has no line), and of_selected_path then gives the tree's own path. Returns 0, -5 when no node of the tree matches (the selection does not move), -2 when the component is not created
of_selected_path ( ) → stringThe path of the selected node, read LIVE: an XPath 1.0 location path to hand as it is to n_pbt_xml.of_get_value on the same document. EVERY line has its own: /order/lines/line[2] when a name repeats, /order/@id for an attribute, /p/text()[2] for a text, /order/comment()[1], /order/processing-instruction('x')[1], /comment()[1] before the root. An element in a DEFAULT namespace is written *[local-name()='Body'] — a bare name matches nothing in XPath; a prefixed name (soap:Body) is kept when its prefix designates the same namespace, otherwise the step names the namespace too (namespace-uri()). A closing tag gives its element. Empty when nothing is selected, and for the XML declaration or the DOCTYPE (not nodes)
of_selected_value ( ) → stringThe value of the selection, read LIVE and decoded — what n_pbt_xml.of_get_value reads at of_selected_path: an attribute's value, the text of a LEAF element (CDATA included, blanks kept), the text of a text line, a comment or a processing instruction; an element shown <x/> that holds only line breaks gives them, as n_pbt_xml does. Empty for an element with children, or when nothing is selected
of_selected_xml ( ) → stringThe XML of the selected node, read LIVE: an element with everything it holds, an attribute as name="value", a text escaped, a comment, a CDATA or a processing instruction as written — what you copy from an XML editor. Empty when nothing is selected
of_selected_kind ( ) → stringWhat the selected node is, read LIVE: KIND_ELEMENT, KIND_ATTRIBUTE, KIND_TEXT, KIND_CDATA, KIND_COMMENT, KIND_PI (a processing instruction), KIND_DECLARATION (the XML declaration) or KIND_DOCTYPE. Empty when nothing is selected
of_selected_name ( ) → stringThe qualified name of the selected node, read LIVE: an element or an attribute as written (soap:Body, id), the target of a processing instruction. Empty for a text, a CDATA, a comment, the declaration, the DOCTYPE, or when nothing is selected
of_selected_namespace ( ) → stringThe namespace URI of the selected element or attribute, read LIVE (http://schemas.xmlsoap.org/soap/envelope/). Empty when it has none (an attribute without a prefix has none), for any other node, or when nothing is selected
of_copy ( ) → longPuts the XML of the selection on the clipboard, like Ctrl+C in the tree (the text of of_selected_xml); a piece of text highlighted with the mouse is what Ctrl+C copies. Returns 0, -4 if nothing is selected, -2 if the component is not created
of_copy_path ( ) → longPuts the PATH of the selected node on the clipboard (/order/lines/line[2], /order/@id), an XPath ready for n_pbt_xml. Returns 0, -4 if nothing is selected or if the node has no path (the XML declaration, the DOCTYPE), -2 if the component is not created
of_match_count ( ) → longReturns how many OCCURRENCES the current search found (two on one line count two), read LIVE — the 12 of a 3 / 12 status line. 0 without a search
of_match_index ( ) → longReturns the 1-based position of the current match, read LIVE — the 3 of a 3 / 12 status line. 0 with no match

Events #

EventWhen
ue_node_clicked (string as_path)The user clicked a node, or pressed Enter on a selected leaf: its XPath (/order/lines/line[2]); an attribute, a text, a comment or a processing instruction gives its own (/order/@id, /order/comment()[1]), a closing tag its element. Hand it to n_pbt_xml.of_get_value on the same document
ue_node_toggled (string as_path, boolean ab_expanded)An element was folded (ab_expanded = false) or opened (true): by the user (its + / − marker, the arrows, Enter or Space) or by of_expand_path / of_collapse_path. of_expand_all, of_collapse_all and of_expand_to_level do not raise it: no gesture folds the whole tree
ue_node_rclicked (string as_path, long al_x, long al_y)A right click on a node, or the Menu key (Shift+F10) in the tree: the node is selected first (ue_selection_changed when the selection moved), as_path is its path, al_x / al_y the point on the SCREEN, in pixels. Open your own menu there (a u_pbt_contextmenu): the tree has none
ue_layout_changed (string as_layout_json)The folds changed — a gesture, an order of your code (of_collapse_all included), a new document, of_set_layout: as_layout_json is the whole layout, as of_get_layout gives it, ready to store. A change of selection or of scrolling does not raise it
ue_selection_changed (string as_path)The selection moved without a click, by the user or by your code: arrows, Home/End, Page Up/Down, of_select_path, a step of of_find_xpath, or a fold that hides the selected line (the selection moves onto the folded element). Raised only when the selection really changes; a new document starts with nothing selected and does not raise it — a mouse click reports ue_node_clicked
ue_search_result (long al_count, long al_index)A search started or moved: al_count occurrences in all, the current one is al_index (1-based, 0 when none) — enough to show “3 / 12”; of_find_xpath raises it too (al_count = the nodes found), and (0, 0) when it ends; when a search closes (Escape in the box, of_clear_search, of_reset, ib_search_enabled = false), (0, 0) once
ue_error (string as_message)The text in is_xml is not valid XML: the message says where, in the display language (“Invalid XML: line 3, column 16 (…)”, the engine's own detail between brackets), and the tree shows the source around that line, the faulty one marked. Also raised when the document is too large to be shown

Example #

Explore an API response #

// Show the XML an API answered, or nothing if the call failed
if inv_rest.of_get(/*url*/ "https://api.example.com/orders/4152") = 200 then
	uo_xml.is_xml = inv_rest.of_response_text()
	uo_xml.of_collapse_all()          // the reader opens what interests them
else
	uo_xml.of_clear()
end if

Read the value of a clicked node #

// Instance variable of the window : the answer, loaded ONCE by n_pbt_xml
n_pbt_xml inv_xml

// open event of the window : n_pbt_xml is created once, owned by the window
inv_xml = create n_pbt_xml
inv_xml.ipo_owner = this

// When the answer arrives : the tree shows it, n_pbt_xml loads the same text once
uo_xml.is_xml = inv_rest.of_response_text()
inv_xml.of_load(/*xml*/ inv_rest.of_response_text())

// ue_node_clicked of uo_xml : the value at the clicked path, nothing loaded again
st_value.text = inv_xml.of_get_value(/*xpath*/ as_path)

// or, without a second parser : the value of the selection, decoded
st_value.text = uo_xml.of_selected_value()

Search whole words, case included #

// Whole words only, with the same case : "id" is not found inside "user_id"
uo_xml.ib_find_match_case = true
uo_xml.ib_find_whole_word = true
uo_xml.of_search(/*query*/ "id")

Keep the folds when the response is refreshed #

// Local variables
string ls_layout

// The folds, the selected node and the line at the top, kept before the new text
ls_layout = uo_xml.of_get_layout()
uo_xml.is_xml = inv_rest.of_response_text()

// The same elements fold again ; a path the new text no longer has is ignored
uo_xml.of_set_layout(/*layout_json*/ ls_layout)

Find every node of an XPath #

// Local variables
long ll_found

// Every order line of more than one item : highlighted, the first one selected
ll_found = uo_xml.of_find_xpath(/*xpath*/ "//line[@qty > 1]")

// A Next button walks them, like F3 ; ue_search_result feeds a "2 / 5" status line
if ll_found > 1 then uo_xml.of_search_next()

// What is selected, without a second parser
st_kind.text = uo_xml.of_selected_kind() + " " + uo_xml.of_selected_name()

A menu on a node #

// ue_node_rclicked of uo_xml : the node is selected, open YOUR menu at that point of the screen
uo_menu.of_show(/*x*/ al_x, /*y*/ al_y)

// ue_item_selected of uo_menu : copy the XML of the node, or its path for n_pbt_xml
choose case as_keys
	case "copy"
		uo_xml.of_copy()
	case "copypath"
		uo_xml.of_copy_path()
end choose

Good practice #


Inherited from the common base #

These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.

MembersRoleDetailed in
of_resetPut the component back to zero3.6 Resetting a component: of_reset()
of_register_shortcut · of_clear_shortcutsThe component's keyboard chords3.5 Keyboard shortcuts
of_is_created · of_is_ready · of_get_last_errorWhether it was born, whether it is ready, what failed3.7 Diagnostics
of_save_as_png · of_save_as_jpgExport the rendering as an image3.8 Exporting the rendering as an image
of_set_redrawGroup changes into a single repaint3.10 Best practices
of_preload_iconsIcons shown with no delayInstant display: of_icon
of_set_translationTranslate one of the component's labels5.2 Adapting a label: of_set_translation
of_focus_webviewGive the component the focus6.4 Keyboard and focus
of_print · of_print_to_pdfPrint, or write a PDF6.9 Printing
of_set_property · of_get_property · of_component_nameDriving a property by its name3.1 The property engine
is_accessible_name · is_accessible_descriptionThe name and description a screen reader says3.4 Optional properties and events

← Component reference · Guide contents