xml — n_pbt_xml #
← Riferimento dei componenti · Sommario della guida
Scrivere un XML elemento per elemento — aperture, attributi, testo, chiusure — con l'escaping fatto per te, poi rileggerne uno con vero XPath:
of_load,of_get_value,of_get_attr,of_count, e numeri e date letti allo stesso modo su ogni macchina (of_get_decimal,of_get_date). PowerBuilder ha PBDOM (un DOM senza XPath, un'estensione PBNI da distribuire) eXMLParseString; questo dà XPath 1.0 e gli spazi dei nomi senza nulla da distribuire, appoggiandosi a DOMParser e document.evaluate del motore WebView2, chiamati in modo sincrono.
▶ Vederlo dal vivo — Applicazione dimostrativa, riquadro XML: i risultati, il codice che li produce e questa pagina, fianco a fianco.
In breve #
Il lato build è PowerScript puro (assemblare una stringa non richiede motore). Il lato lettura apre una pagina nascosta alla prima query. L'XPath è la versione 1.0, come la valuta il browser. C'è un documento alla volta: una lettura su un documento costruito lo carica prima nella pagina, diventa il documento caricato, e il of_start_element seguente ne inizia uno nuovo. Una lettura è rifiutata finché un elemento del documento costruito è ancora aperto (-4, vuoto o false, e of_get_last_error()): chiudete prima i vostri elementi — nulla va perso. of_xml e of_pretty, che lavorano su una copia, restano disponibili.
Avvio rapido #
// Local variables
n_pbt_xml lnv_xml
// Create the object once, free it when done
lnv_xml = create n_pbt_xml
// Read : load, then query with XPath
lnv_xml.of_load(/*xml*/ '<order id="4152"><customer>Ada</customer></order>')
IF lnv_xml.of_is_valid() THEN
MessageBox("Customer", lnv_xml.of_get_value(/*xpath*/ "/order/customer")) // Ada
MessageBox("Id", lnv_xml.of_get_attr(/*xpath*/ "/order", /*name*/ "id")) // 4152
END IF
// Build : element by element, escaping done for you
lnv_xml.of_clear()
lnv_xml.of_start_element(/*name*/ "order")
lnv_xml.of_element_attr(/*name*/ "id", /*value*/ "4152")
lnv_xml.of_leaf(/*name*/ "customer", /*text*/ "Ada & Co")
lnv_xml.of_end_element()
// lnv_xml.of_xml() -><order id="4152"><customer>Ada & Co</customer></order>
// Free the object
destroy lnv_xml
Proprietà #
| Proprietà | Tipo | Predefinito | Ruolo |
|---|---|---|---|
ipo_owner | powerobject | null | L'oggetto visuale per cui lavora questo helper: la licenza si verifica sulla sua classe. Da impostare prima della prima lettura; impostato più tardi, viene trasmesso alla lettura successiva. Necessario solo nell'applicazione dimostrativa; una chiave di sviluppo o di runtime sblocca la lettura senza di esso. Non sbloccata, la lettura è in modalità demo — documenti di al più 65 536 caratteri, modifiche comprese; of_is_valid è falso e of_pretty vuoto per un documento costruito più lungo. La costruzione non ne ha bisogno: è PowerScript puro |
Costruire un documento #
| Membro | Ruolo |
|---|---|
of_get_last_error ( ) → string | Perché l'ultima lettura ha reso vuoto, false, 0 o un codice negativo: documento non valido, XPath rifiutato dal motore, XPath senza corrispondenza, niente caricato, limite demo, pagina che non ha risposto. Vuoto dopo una lettura riuscita. Anche il builder vi scrive quando rifiuta un nome di elemento o di attributo non valido |
of_start_element (string as_name) | Apre un elemento (gli elementi si annidano: un tag aperto viene chiuso prima). Un nome non valido (vuoto, con uno spazio, un carattere vietato, più di un :, un : all'inizio o alla fine) è rifiutato: of_get_last_error() dice perché, e l'elemento resta fuori dal documento con tutto ciò che contiene; lo stesso per un secondo elemento in cima, una volta chiusa la radice: un documento ha una sola radice |
of_element_attr (string as_name, string as_value) | Aggiunge un attributo all'elemento aperto, valore con escape — a capo e tabulazioni compresi, perché si rileggano tali e quali (prima di ogni figlio o testo). Un nome non valido è rifiutato (of_get_last_error()); lo stesso nome dato due volte tiene UN solo attributo, con il secondo valore. Dato dopo un figlio o un testo, o senza elemento aperto, è lasciato fuori e of_get_last_error() lo dice. Overload: decimal, date, datetime, boolean, scritti come da of_leaf |
of_element_text (string as_text) | Il contenuto testuale dell'elemento corrente, con escape; i caratteri di controllo vietati da XML sono rimossi (uno solo rendeva non valido tutto il documento). Senza elemento aperto il testo è lasciato fuori, e of_get_last_error() lo dice |
of_end_element ( ) | Chiude l'elemento corrente (vuoto, si auto-chiude <name/>) |
of_leaf (string as_name, string as_text) | Un elemento foglia in una chiamata — <name>testo</name>, con escaping. Overload: un decimal, una date, un datetime o un boolean, scritti come li scrive XML Schema su qualunque macchina — 690.5 (un punto), 2026-10-31, 2026-10-31T14:30:00, true; un NULL scrive un elemento vuoto |
of_clear ( ) → long | Svuota il documento — costruito o caricato — per iniziarne un altro; un documento caricato lascia anche la pagina. Rende 0 |
of_xml ( ) → string | Il documento così com'è: ciò che hai costruito o caricato (of_load), dopo ogni modifica — l'unica uscita, da inviare, memorizzare o riscrivere. Un documento costruito non necessita di pagina (ogni elemento aperto è chiuso) ; uno caricato è serializzato dal motore. of_pretty è la forma indentata |
Leggere un documento (XPath) #
| Membro | Ruolo |
|---|---|
of_load (string as_xml) → long | Carica un testo XML (analizzato dal DOMParser del motore). Rende 0 se ben formato, -5 se vuoto, -4 se XML non valido (o, in modalità demo, troppo lungo una volta sviluppate le entità), -2 se la pagina nascosta non ha risposto. Su un codice negativo NON resta nulla: né un documento caricato prima, né uno costruito a metà. Ogni chiamata alla pagina attende al massimo 5 secondi: un documento di decine di MB, soprattutto in un'applicazione a 32 bit, può rendere -2 |
of_is_valid ( ) → boolean | Vero quando è tenuto un documento ben formato — caricato con of_load, o costruito (viene allora caricato nella pagina, come da ogni lettura). Falso se non c'è nulla, o se il documento costruito non è ben formato o ha ancora un elemento aperto — e, in modalità demo, per un documento costruito di più di 65 536 caratteri |
of_exists (string as_xpath) → boolean | Vero quando l'XPath corrisponde ad almeno un nodo. Un'espressione che rende un VALORE (count(//line)) non è un nodo: leggetela con of_get_value |
of_get_value (string as_xpath) → string | Il contenuto testuale del PRIMO nodo corrispondente. Vuoto se nessuno (of_get_last_error() lo dice). Un XPath che rende un VALORE lo rende come testo: count(//line) → 3, sum(//@qty), boolean(//paid) → true. / rende il testo del documento intero; un'espressione che non è un numero (un sum() su un testo) rende vuoto con il suo motivo, mai NaN. Un numero, una data, un booleano si leggono allo stesso modo su ogni macchina con of_get_number, of_get_decimal, of_get_date… |
of_get_attr (string as_xpath, string as_name) → string | Il valore dell'attributo as_name sul primo nodo corrispondente. Vuoto se il nodo o l'attributo è assente — of_get_last_error() dice allora «no node matched» o «no such attribute»; un attributo scritto vuoto (a="") rende vuoto senza motivo. Un nome vuoto è rifiutato allo stesso modo |
of_count (string as_xpath) → long | Quanti nodi seleziona l'XPath. 0 se nessuno; -4 se nulla è caricato, se un elemento del documento costruito è ancora aperto o se il motore ha rifiutato l'XPath, -2 se la pagina non ha risposto; of_get_last_error() dice quale |
of_name (string as_xpath) → string | Il nome del tag del primo nodo corrispondente. Vuoto se nessuno |
of_pretty ( ) → string | Il documento così com'è — costruito o caricato, ciò che rende of_xml — reindentato per la lettura. CDATA, commenti, istruzioni di elaborazione e dichiarazione XML sono conservati, e un elemento che contiene testo è scritto su una riga, tale e quale; ciò che viene reindentato sono gli spazi bianchi TRA gli elementi — tranne in un elemento marcato xml:space="preserve", scritto tale e quale. Vuoto se non c'è nulla, se un documento costruito non è ben formato, e in modalità demo per un documento di più di 65 536 caratteri |
Numeri, date e booleani #
XML Schema scrive un numero con un punto e una data in ISO 8601, qualunque sia il paese. Dec("690.50") o Date("2026-10-31") dipendono invece dalle impostazioni internazionali della macchina. Questi lettori verificano il valore rispetto al suo tipo e lo rendono allo stesso modo su ogni macchina; un valore assente, vuoto o di un altro tipo rende NULL, e of_get_last_error() dice perché. Funziona anche un XPath che rende un valore (sum(//qty)). Per scrivere: of_leaf, of_element_attr e of_set_value accettano un decimal, una date, un datetime o un boolean.
| Membro | Ruolo |
|---|---|
of_get_number (string as_xpath) → double | Il numero come double: 690.50, -1.5E3, +.5; spazi intorno ignorati; 12 kg, 1,5, INF sono rifiutati |
of_get_decimal (string as_xpath) → decimal | Il numero come decimal, ogni cifra conservata (un importo non perde mai i centesimi); rifiutato oltre le 28 cifre di un decimal |
of_get_longlong (string as_xpath) → longlong | L'intero come longlong, ogni cifra conservata (anche un id oltre 2^53); 2.5 è rifiutato, non troncato |
of_get_boolean (string as_xpath) → boolean | true o 1 → true, false o 0 → false; tutto il resto (yes, Y) rende NULL |
of_get_date (string as_xpath) → date | 2026-10-31, o la data di una data-ora; un fuso (Z, +02:00) è accettato senza essere applicato. Rifiutati: un giorno che non esiste (2026-02-30), un anno fuori da 1000-3000 |
of_get_datetime (string as_xpath) → datetime | 2026-10-10T14:30:00, con o senza frazione di secondo, 2026-10-10 14:30, o una data sola (mezzanotte); l'ora è quella SCRITTA: un fuso non è applicato, come lo legge n_pbt_json |
// Local variables
n_pbt_xml lnv_xml
decimal ldc_total
date ld_due
// Create the object once, free it when done
lnv_xml = create n_pbt_xml
// Write : a point and ISO 8601, whatever the regional settings
lnv_xml.of_start_element(/*name*/ "invoice")
lnv_xml.of_element_attr(/*name*/ "paid", /*value*/ false)
lnv_xml.of_leaf(/*name*/ "total", /*value*/ 690.50)
lnv_xml.of_leaf(/*name*/ "due", /*value*/ Date(2026, 10, 31))
lnv_xml.of_end_element()
// lnv_xml.of_xml() -> <invoice paid="false"><total>690.5</total><due>2026-10-31</due></invoice>
// Read them back as values you can compute with
ldc_total = lnv_xml.of_get_decimal(/*xpath*/ "/invoice/total")
ld_due = lnv_xml.of_get_date(/*xpath*/ "/invoice/due")
// A value that is not of its type is NULL : is_last_error says why
IF IsNull(ldc_total) THEN MessageBox("Total", lnv_xml.of_get_last_error())
// Free the object
destroy lnv_xml
Più nodi, e il documento #
| Membro | Ruolo |
|---|---|
of_get_values (string as_xpath, ref string as_values[]) → long | Il contenuto testuale di OGNI nodo corrispondente, in as_values; restituisce il conteggio, 0 se nessuno, -4 se nulla è caricato o se l'XPath è rifiutato, -2 se la pagina non ha risposto. Dove of_get_value rende solo il primo |
of_get_attrs (string as_xpath, string as_name, ref string as_values[]) → long | Il valore dell'attributo as_name su OGNI nodo corrispondente (l'id di ogni riga), vuoto per un nodo che non lo ha; restituisce il conteggio, 0 se nessuno, -5 su un nome vuoto, -4 se nulla è caricato o se l'XPath è rifiutato, -2 se la pagina non ha risposto |
of_get_attr_names (string as_xpath, ref string as_names[]) → long | I nomi di tutti gli attributi del primo nodo corrispondente (enumerazione); restituisce il conteggio, 0 se il nodo non ne ha o nessun nodo corrisponde (of_get_last_error() lo dice), -4 se nulla è caricato, se l'XPath è rifiutato o se il nodo non è un elemento, -2 se la pagina non ha risposto |
Modificare un documento #
Il lato scrittura cambia l'albero caricato sul posto; of_xml ne rende il risultato. Ognuna mira al PRIMO nodo corrispondente (tranne of_remove, che li prende tutti), rende 0 al successo, -4 se nulla corrisponde o se la modifica è rifiutata (of_get_last_error() dice perché), -5 su argomento vuoto, -2 se la pagina non ha risposto. Ciò che una modifica scrive segue la regola del builder: i caratteri di controllo vietati da XML sono rimossi, e un CR è scritto in modo da rileggersi.
| Membro | Ruolo |
|---|---|
of_set_value (string as_xpath, string as_text) → long | Imposta il testo del primo nodo corrispondente (i suoi figli sono sostituiti). Overload: decimal, date, datetime, boolean, scritti come da of_leaf |
of_set_attr (string as_xpath, string as_name, string as_value) → long | Imposta (o aggiunge) un attributo sul primo nodo corrispondente. Un nome con prefisso (xsi:type) va nello spazio dei nomi che il prefisso ha in quel nodo (o legato con of_register_namespace); un prefisso non legato da nessuna parte è rifiutato (-4, of_get_last_error()) |
of_remove_attr (string as_xpath, string as_name) → long | Rimuove un attributo dal primo nodo corrispondente; -4 e «no such attribute» se il nodo non lo ha |
of_add_child (string as_xpath, string as_tag, string as_text) → long | Aggiunge un elemento figlio <as_tag>as_text</as_tag> sotto il primo nodo corrispondente (il figlio eredita lo spazio dei nomi e il prefisso del genitore; un tag con prefisso p:item prende lo spazio dei nomi del suo prefisso, o -4 se non è legato da nessuna parte). -4 anche quando il nodo non può avere figli (un attributo, un testo) o il tag non è un nome valido |
of_add_xml (string as_xpath, string as_fragment) → long | Innesta un frammento XML già formato (uno o più elementi fratelli) sotto il primo nodo corrispondente — ciò che of_add_child non può fare, prendendo solo un tag e un testo. Il frammento deve essere ben formato; eredita gli spazi dei nomi in vigore sul suo bersaglio, come of_add_child (<line> sotto <order xmlns='urn:acme'> è in urn:acme, <s:Item/> sotto un s:Body SOAP non dichiara nulla); un prefisso legato con of_register_namespace, o dichiarato altrove nel documento, non dichiara nulla neanch'esso |
of_remove (string as_xpath) → long | Rimuove TUTTI i nodi corrispondenti (una riga, un ramo obsoleto, un attributo). Rende quanti ne sono stati davvero rimossi (>= 0; su 0, of_get_last_error() dice perché), -4 se nulla è caricato, -5 su un XPath vuoto, -2 se la pagina non ha risposto. L'elemento radice resta: of_clear svuota un documento |
Namespace #
Un XPath con prefisso (SOAP, un'API aziendale) risolve da solo un prefisso che il documento dichiara (xmlns:s="…", su qualsiasi elemento). ⚠️ La trappola più frequente: lo spazio dei nomi PREDEFINITO. <order xmlns="urn:acme"><customer>… non ha alcun prefisso, eppure /order/customer non corrisponde a NULLA: XPath 1.0 non ha spazio dei nomi predefinito. Legate un prefisso a scelta con of_register_namespace("a", "urn:acme") e scrivete /a:order/a:customer. of_clear_namespaces dimentica i legami. Non c'è XSLT: Chromium lo rimuove dal motore (trasformate lato server, o tramite MSXML in OLE: Msxml2.DOMDocument.6.0, transformNode). Non c'è validazione per schema XSD: il motore non ne ha.
| Membro | Ruolo |
|---|---|
of_register_namespace (string as_prefix, string as_uri) → long | Lega un prefisso all'URI del suo spazio dei nomi, perché un XPath con prefisso si risolva. Rende 0, -5 su un prefisso o un URI vuoto, -2 se la pagina non ha risposto. I legami durano fino a of_clear_namespaces o of_reset — of_close non li perde |
of_clear_namespaces ( ) → long | Dimentica tutti i prefissi registrati: un prefisso che il documento non dichiara non corrisponde più a nulla finché non è legato. Rende 0, -2 se la pagina non ha risposto. Nessuna pagina viene aperta per questo |
// Local variables
n_pbt_xml lnv_xml
string ls_soap, ls_ok, ls_name, ls_out
// ls_soap holds the response of a web service
lnv_xml = create n_pbt_xml
// A SOAP response : the prefix declared by the document resolves on its own
lnv_xml.of_load(/*xml*/ ls_soap)
ls_ok = lnv_xml.of_get_value(/*xpath*/ "//s:Body/result/status")
// A DEFAULT namespace (xmlns="urn:acme") : bind a prefix of your choice
lnv_xml.of_load(/*xml*/ '<order xmlns="urn:acme"><customer>Ada</customer></order>')
lnv_xml.of_register_namespace(/*prefix*/ "a", /*uri*/ "urn:acme")
ls_name = lnv_xml.of_get_value(/*xpath*/ "/a:order/a:customer") // Ada
// Mutate, then read the result back
lnv_xml.of_set_value(/*xpath*/ "/a:order/a:customer", /*text*/ "Grace")
lnv_xml.of_add_child(/*xpath*/ "/a:order", /*tag*/ "total", /*text*/ "690.50")
// Graft a whole fragment at once (of_add_child adds only one tag)
lnv_xml.of_add_xml(/*xpath*/ "/a:order", /*fragment*/ '<lines xmlns="urn:acme"><line sku="1">A</line><line sku="2">B</line></lines>')
ls_out = lnv_xml.of_xml()
// Free the object
destroy lnv_xml
La pagina nascosta #
| Membro | Ruolo |
|---|---|
of_open ( ) → long | Crea la pagina nascosta (lato lettura). Facoltativo — la prima lettura lo fa. Restituisce l'handle (> 0) o -2 se non è stato possibile crearla (of_get_last_error() dice perché) |
of_is_open ( ) → boolean | Vero appena la pagina nascosta esiste |
of_close ( ) → long | Libera la pagina nascosta. Il build continua senza di essa, e un documento caricato non va perso: è conservato come testo, e la lettura seguente lo ricarica, con i prefissi legati da of_register_namespace. Fatto per voi alla distruzione Rende 0 una volta fatto. |
of_reset ( ) → long | Ritorno ai valori predefiniti: il builder svuotato, il documento caricato abbandonato, i prefissi registrati dimenticati, of_get_last_error() svuotato. La pagina nascosta resta aperta; of_close la libera Rende 0 una volta fatto. |
Ambito. L'XML si legge tramite il motore (DOMParser, XPath):
n_pbt_xmlapre una pagina nascosta alla prima lettura, a differenza di json, che analizza in PowerScript puro. Per mostrare un XML come albero comprimibile, vedi xmltree.