PBToolboxAI v5 ← Site

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) e XMLParseString; 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 &amp; Co</customer></order>

// Free the object
destroy lnv_xml

Proprietà #

ProprietàTipoPredefinitoRuolo
ipo_ownerpowerobjectnullL'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 #

MembroRuolo
of_get_last_error ( ) → stringPerché 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 ( ) → longSvuota il documento — costruito o caricato — per iniziarne un altro; un documento caricato lascia anche la pagina. Rende 0
of_xml ( ) → stringIl 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) #

MembroRuolo
of_load (string as_xml) → longCarica 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 ( ) → booleanVero 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) → booleanVero 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) → stringIl 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) → stringIl 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) → longQuanti 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) → stringIl nome del tag del primo nodo corrispondente. Vuoto se nessuno
of_pretty ( ) → stringIl 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.

MembroRuolo
of_get_number (string as_xpath) → doubleIl numero come double: 690.50, -1.5E3, +.5; spazi intorno ignorati; 12 kg, 1,5, INF sono rifiutati
of_get_decimal (string as_xpath) → decimalIl 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) → longlongL'intero come longlong, ogni cifra conservata (anche un id oltre 2^53); 2.5 è rifiutato, non troncato
of_get_boolean (string as_xpath) → booleantrue o 1 → true, false o 0 → false; tutto il resto (yes, Y) rende NULL
of_get_date (string as_xpath) → date2026-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) → datetime2026-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 #

MembroRuolo
of_get_values (string as_xpath, ref string as_values[]) → longIl 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[]) → longIl 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[]) → longI 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.

MembroRuolo
of_set_value (string as_xpath, string as_text) → longImposta 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) → longImposta (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) → longRimuove 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) → longAggiunge 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) → longInnesta 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) → longRimuove 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.

MembroRuolo
of_register_namespace (string as_prefix, string as_uri) → longLega 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 ( ) → longDimentica 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 #

MembroRuolo
of_open ( ) → longCrea 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 ( ) → booleanVero appena la pagina nascosta esiste
of_close ( ) → longLibera 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 ( ) → longRitorno 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_xml apre una pagina nascosta alla prima lettura, a differenza di json, che analizza in PowerScript puro. Per mostrare un XML come albero comprimibile, vedi xmltree.

← Riferimento dei componenti · Sommario della guida