xml — n_pbt_xml #
← Referencia de componentes · Índice de la guía
Escribir un XML elemento por elemento — aperturas, atributos, texto, cierres — con el escapado hecho por usted, y luego leer uno con XPath real:
of_load,of_get_value,of_get_attr,of_count, y números y fechas leídos igual en cualquier máquina (of_get_decimal,of_get_date). PowerBuilder tiene PBDOM (un DOM sin XPath, una extensión PBNI que hay que desplegar) yXMLParseString; este da XPath 1.0 y los espacios de nombres sin nada que desplegar, apoyándose en DOMParser y document.evaluate del motor WebView2, llamados de forma sincrónica.
▶ Verlo en vivo — Aplicación de demostración, mosaico XML: los resultados, el código que los produce y esta página, lado a lado.
En resumen #
El lado de construcción es PowerScript puro (armar una cadena no necesita motor). El lado de lectura abre una página oculta en la primera consulta. El XPath es la versión 1.0, tal como lo evalúa el navegador. Hay un documento a la vez: una lectura sobre un documento construido lo carga primero en la página, se convierte en el documento cargado, y el of_start_element siguiente empieza uno nuevo. Una lectura se rechaza mientras un elemento del documento construido siga abierto (-4, vacío o false, e of_get_last_error()): cierre primero sus elementos — no se pierde nada. of_xml y of_pretty, que trabajan sobre una copia, siguen disponibles.
Inicio rápido #
// 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
Propiedades #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
ipo_owner | powerobject | null | El objeto visual para el que trabaja esta utilidad: la licencia se comprueba en su clase. Se asigna antes de la primera lectura; asignado más tarde, se transmite en la lectura siguiente. Necesario solo en la aplicación de demostración; una clave de desarrollo o de ejecución desbloquea la lectura sin él. Sin desbloquear, la lectura está en modo demo — documentos de 65 536 caracteres como máximo, modificaciones incluidas; of_is_valid es falso y of_pretty vacío para un documento construido más largo. La construcción no lo necesita: es PowerScript puro |
Construir un documento #
| Miembro | Función |
|---|---|
of_get_last_error ( ) → string | Por qué la última lectura devolvió vacío, false, 0 o un código negativo: documento mal formado, XPath rechazado por el motor, XPath sin coincidencia, nada cargado, límite demo, página que no respondió. Vacío tras una lectura con éxito. El builder también escribe aquí cuando rechaza un nombre de elemento o de atributo no válido |
of_start_element (string as_name) | Abre un elemento (los elementos se anidan: una etiqueta abierta se cierra primero). Un nombre no válido (vacío, con un espacio, un carácter prohibido, más de un :, un : al principio o al final) se rechaza: of_get_last_error() dice por qué, y el elemento queda fuera del documento con todo lo que contiene; también un segundo elemento en la cima, una vez cerrada la raíz: un documento tiene una sola raíz |
of_element_attr (string as_name, string as_value) | Añade un atributo al elemento abierto, valor escapado — saltos de línea y tabulaciones incluidos, para que se relean tal cual (antes de cualquier hijo o texto). Un nombre no válido se rechaza (of_get_last_error()); el mismo nombre dado dos veces deja UN solo atributo, con el segundo valor. Dado tras un hijo o un texto, o sin elemento abierto, se deja fuera e of_get_last_error() lo dice. Sobrecargas: decimal, date, datetime, boolean, escritos como los escribe of_leaf |
of_element_text (string as_text) | El contenido de texto del elemento actual, escapado; los caracteres de control que XML prohíbe se eliminan (uno solo dejaba todo el documento mal formado). Sin elemento abierto el texto se deja fuera, e of_get_last_error() lo dice |
of_end_element ( ) | Cierra el elemento actual (vacío, se auto-cierra <name/>) |
of_leaf (string as_name, string as_text) | Un elemento hoja en una llamada — <name>texto</name>, escapado. Sobrecargas: un decimal, una date, un datetime o un boolean, escritos como los escribe XML Schema en cualquier máquina — 690.5 (un punto), 2026-10-31, 2026-10-31T14:30:00, true; un NULL escribe un elemento vacío |
of_clear ( ) → long | Vacía el documento — construido o cargado — para empezar otro; un documento cargado sale también de la página. Devuelve 0 |
of_xml ( ) → string | El documento tal cual: lo que construyó o cargó (of_load), tras cualquier cambio — la salida única, para enviar, almacenar o reescribir. Un documento construido no necesita página (todo elemento abierto se cierra) ; uno cargado lo serializa el motor. of_pretty da la forma indentada |
Leer un documento (XPath) #
| Miembro | Función |
|---|---|
of_load (string as_xml) → long | Carga un texto XML (analizado por el DOMParser del motor). Devuelve 0 si está bien formado, -5 si está vacío, -4 si no es XML válido (o, en modo demo, demasiado largo una vez desarrolladas sus entidades), -2 si la página oculta no respondió. Con un código negativo NO queda nada: ni un documento cargado antes, ni uno construido a medias. Cada llamada a la página espera 5 segundos como máximo: un documento de decenas de MB, sobre todo en una aplicación de 32 bits, puede devolver -2 |
of_is_valid ( ) → boolean | Verdadero cuando se tiene un documento bien formado — cargado con of_load, o construido (se carga entonces en la página, como en toda lectura). Falso si no hay nada, o si el documento construido está mal formado o aún tiene un elemento abierto — y, en modo demo, para un documento construido de más de 65 536 caracteres |
of_exists (string as_xpath) → boolean | Verdadero cuando el XPath coincide con al menos un nodo. Una expresión que devuelve un VALOR (count(//line)) no es un nodo: léala con of_get_value |
of_get_value (string as_xpath) → string | El contenido de texto del PRIMER nodo coincidente. Vacío si ninguno (of_get_last_error() lo dice). Un XPath que devuelve un VALOR lo da como texto: count(//line) → 3, sum(//@qty), boolean(//paid) → true. / devuelve el texto del documento entero; una expresión que no es un número (un sum() sobre un texto) devuelve vacío con su motivo, nunca NaN. Un número, una fecha, un booleano se leen igual en cualquier máquina con of_get_number, of_get_decimal, of_get_date… |
of_get_attr (string as_xpath, string as_name) → string | El valor del atributo as_name del primer nodo coincidente. Vacío si el nodo o el atributo está ausente — of_get_last_error() dice entonces «no node matched» o «no such attribute»; un atributo escrito vacío (a="") devuelve vacío sin motivo. Un nombre vacío se rechaza igual |
of_count (string as_xpath) → long | Cuántos nodos selecciona el XPath. 0 si ninguno; -4 si no hay nada cargado, si un elemento del documento construido sigue abierto o si el motor rechazó el XPath, -2 si la página no respondió; of_get_last_error() dice cuál |
of_name (string as_xpath) → string | El nombre de etiqueta del primer nodo coincidente. Vacío si ninguno |
of_pretty ( ) → string | El documento tal cual — construido o cargado, lo que devuelve of_xml — reindentado para su lectura. CDATA, comentarios, instrucciones de procesamiento y la declaración XML se conservan, y un elemento que contiene texto se escribe en una línea, tal cual; lo que se reindenta son los blancos ENTRE elementos — salvo en un elemento marcado xml:space="preserve", escrito tal cual. Vacío si no hay nada, si un documento construido no está bien formado, y en modo demo para un documento de más de 65 536 caracteres |
Números, fechas y booleanos #
XML Schema escribe un número con un punto y una fecha en ISO 8601, sea cual sea el país. Dec("690.50") o Date("2026-10-31") dependen, en cambio, de la configuración regional de la máquina. Estos lectores comprueban el valor contra su tipo y lo devuelven igual en cualquier máquina; un valor ausente, vacío o de otro tipo devuelve NULL, e of_get_last_error() dice por qué. Un XPath que devuelve un valor (sum(//qty)) también sirve. Para escribir: of_leaf, of_element_attr y of_set_value aceptan un decimal, una date, un datetime o un boolean.
| Miembro | Función |
|---|---|
of_get_number (string as_xpath) → double | El número como double: 690.50, -1.5E3, +.5; blancos alrededor ignorados; 12 kg, 1,5, INF se rechazan |
of_get_decimal (string as_xpath) → decimal | El número como decimal, cada cifra conservada (un importe nunca pierde sus céntimos); rechazado más allá de las 28 cifras de un decimal |
of_get_longlong (string as_xpath) → longlong | El entero como longlong, cada cifra conservada (también un id por encima de 2^53); 2.5 se rechaza, no se trunca |
of_get_boolean (string as_xpath) → boolean | true o 1 → true, false o 0 → false; todo lo demás (yes, Y) devuelve NULL |
of_get_date (string as_xpath) → date | 2026-10-31, o la fecha de una fecha-hora; una zona horaria (Z, +02:00) se acepta sin aplicarse. Rechazados: un día que no existe (2026-02-30), un año fuera de 1000 a 3000 |
of_get_datetime (string as_xpath) → datetime | 2026-10-10T14:30:00, con o sin fracción de segundo, 2026-10-10 14:30, o una fecha sola (medianoche); la hora es la ESCRITA: una zona horaria no se aplica, como la lee 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
Varios nodos, y el documento #
| Miembro | Función |
|---|---|
of_get_values (string as_xpath, ref string as_values[]) → long | El contenido de texto de CADA nodo coincidente, en as_values; devuelve el recuento, 0 si ninguno, -4 si no hay nada cargado o si el XPath se rechazó, -2 si la página no respondió. Donde of_get_value solo devuelve el primero |
of_get_attrs (string as_xpath, string as_name, ref string as_values[]) → long | El valor del atributo as_name en CADA nodo coincidente (el id de cada fila), vacío para un nodo que no lo tiene; devuelve el recuento, 0 si ninguno, -5 con un nombre vacío, -4 si no hay nada cargado o si el XPath se rechazó, -2 si la página no respondió |
of_get_attr_names (string as_xpath, ref string as_names[]) → long | Los nombres de todos los atributos del primer nodo coincidente (enumeración); devuelve el recuento, 0 si el nodo no tiene ninguno o ningún nodo coincide (of_get_last_error() lo dice), -4 si no hay nada cargado, si el XPath se rechazó o si el nodo no es un elemento, -2 si la página no respondió |
Modificar un documento #
El lado de escritura cambia el árbol cargado en el sitio; of_xml devuelve el resultado. Cada una apunta al PRIMER nodo coincidente (salvo of_remove, que los toma todos), devuelve 0 al tener éxito, -4 si nada coincide o si el cambio se rechaza (of_get_last_error() dice por qué), -5 con un argumento vacío, -2 si la página no respondió. Lo que escribe una modificación sigue la regla del builder: los caracteres de control que XML prohíbe se eliminan, y un CR se escribe de modo que se relea.
| Miembro | Función |
|---|---|
of_set_value (string as_xpath, string as_text) → long | Fija el texto del primer nodo coincidente (sus hijos se reemplazan). Sobrecargas: decimal, date, datetime, boolean, escritos como los escribe of_leaf |
of_set_attr (string as_xpath, string as_name, string as_value) → long | Fija (o agrega) un atributo en el primer nodo coincidente. Un nombre con prefijo (xsi:type) va al espacio de nombres que su prefijo tiene en ese nodo (o ligado con of_register_namespace); un prefijo no ligado en ninguna parte se rechaza (-4, of_get_last_error()) |
of_remove_attr (string as_xpath, string as_name) → long | Quita un atributo del primer nodo coincidente; -4 y «no such attribute» si el nodo no lo tiene |
of_add_child (string as_xpath, string as_tag, string as_text) → long | Añade un elemento hijo <as_tag>as_text</as_tag> bajo el primer nodo coincidente (el hijo hereda el espacio de nombres y el prefijo del padre; una etiqueta con prefijo p:item toma el espacio de nombres de su prefijo, o -4 si no está ligado en ninguna parte). -4 también cuando el nodo no puede tener hijos (un atributo, un texto) o la etiqueta no es un nombre válido |
of_add_xml (string as_xpath, string as_fragment) → long | Injerta un fragmento XML ya formado (uno o varios elementos hermanos) bajo el primer nodo coincidente — lo que of_add_child no puede hacer, tomando solo una etiqueta y un texto. El fragmento debe estar bien formado; hereda los espacios de nombres vigentes en su destino, como of_add_child (<line> bajo <order xmlns='urn:acme'> está en urn:acme, <s:Item/> bajo un s:Body SOAP no declara nada); un prefijo ligado con of_register_namespace, o declarado en otra parte del documento, tampoco declara nada |
of_remove (string as_xpath) → long | Quita TODOS los nodos coincidentes (una fila, una rama obsoleta, un atributo). Devuelve cuántos se quitaron realmente (>= 0; con 0, of_get_last_error() dice por qué), -4 si no hay nada cargado, -5 con un XPath vacío, -2 si la página no respondió. El elemento raíz se queda: of_clear vacía un documento |
Espacios de nombres #
Un XPath con prefijo (SOAP, una API empresarial) resuelve por sí solo un prefijo que el documento declara (xmlns:s="…", en cualquier elemento). ⚠️ La trampa más frecuente: el espacio de nombres POR DEFECTO. <order xmlns="urn:acme"><customer>… no tiene prefijo, y sin embargo /order/customer no coincide con NADA: XPath 1.0 no tiene espacio de nombres por defecto. Ligue un prefijo de su elección con of_register_namespace("a", "urn:acme") y escriba /a:order/a:customer. of_clear_namespaces olvida las ligaduras. No hay XSLT: Chromium lo retira del motor (transforme en el servidor, o mediante MSXML en OLE: Msxml2.DOMDocument.6.0, transformNode). No hay validación por esquema XSD: el motor no la tiene.
| Miembro | Función |
|---|---|
of_register_namespace (string as_prefix, string as_uri) → long | Liga un prefijo al URI de su espacio de nombres, para que un XPath con prefijo se resuelva. Devuelve 0, -5 con un prefijo o un URI vacío, -2 si la página no respondió. Las ligaduras duran hasta of_clear_namespaces u of_reset — of_close no las pierde |
of_clear_namespaces ( ) → long | Olvida todos los prefijos registrados: un prefijo que el documento no declara ya no coincide con nada mientras no se ligue. Devuelve 0, -2 si la página no respondió. No se abre ninguna página para ello |
// 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 página oculta #
| Miembro | Función |
|---|---|
of_open ( ) → long | Crea la página oculta (lado lectura). Opcional — la primera lectura lo hace. Devuelve el handle (> 0) o -2 si no se pudo crear (of_get_last_error() dice por qué) |
of_is_open ( ) → boolean | Verdadero en cuanto existe la página oculta |
of_close ( ) → long | Libera la página oculta. La construcción sigue sin ella, y un documento cargado no se pierde: se guarda como texto, y la lectura siguiente lo vuelve a cargar, con los prefijos ligados por of_register_namespace. Se hace por usted al destruir Devuelve 0 una vez hecho. |
of_reset ( ) → long | Vuelta a los valores por defecto: el builder vaciado, el documento cargado descartado, los prefijos registrados olvidados, of_get_last_error() vaciado. La página oculta sigue abierta; of_close la libera Devuelve 0 una vez hecho. |
Alcance. El XML se lee mediante el motor (DOMParser, XPath):
n_pbt_xmlabre una página oculta en la primera lectura, a diferencia de json, que analiza en PowerScript puro. Para mostrar un XML como árbol plegable, vea xmltree.