XML Decoders/es: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: XML Decoders/es
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## XML Decodificadores | |
| 2 | + | ||
| 3 | + | A partir de la revisión de SVN 12582, el lector de XML es capaz de procesar los datos en cualquier codificación mediante el uso de descodificadores externos. Lo que sigue es una breve descripción de cómo funciona. | |
| 4 | + | ||
| 5 | + | ### Decodificadores disponibles | |
| 6 | + | ||
| 7 | + | En la actualidad, un decodificador que utiliza libiconv está disponible. Tiene dos implementaciones distintas. La primera, en la unidad**xmliconv.pas**, utiliza el paquete iconvenc existente y es compatible con Linux, FreeBSD y Darwin. La segunda, en la unidad **xmliconv_windows.pas**, es para Windows. Enlaza a la iconv.dll que debes distribuir con la aplicación. | |
| 8 | + | ||
| 9 | + | ### Estructura del decodificador | |
| 10 | + | ||
| 11 | + | La interacción con los decodificadores externos se hace mediante procedimiento sencillo. Escribir el decodificador es esencialmente escribir la implementación de los tres procedimientos siguientes: | |
| 12 | + | ||
| 13 | + | 1. `GetDecoder` | |
| 14 | + | 2. `Decode` | |
| 15 | + | 3. `Cleanup` (optional) | |
| 16 | + | ||
| 17 | + | Aquí una breve descripción del funcionamiento con un decodificador externo: | |
| 18 | + | ||
| 19 | + | #### GetDecoder | |
| 20 | + | ||
| 21 | + | ``` pascal | |
| 22 | + | function GetDecoder(const AEncoding: string; out Decoder: TDecoder): Boolean; stdcall; | |
| 23 | + | ``` | |
| 24 | + | ||
| 25 | + | En el momento de la iniciación del programa, el decodificador se registra llamando al procedimiemto `XMLRead.RegisterDecoder` y pasando la función `GetDecoder` como argumento. Cada vez que el lector se encuentra con una etiqueta de codificación que no controla internamente, llama a todas las funciones `GetDecoder` registradas en el mismo orden en que se registraron, hasta que una de ellas devuelve **true**. Los argumentos de la función `GetDecoder` son el nombre de la codificación y el registro `TDecoder` que la función debe llenar. El nombre de codificación se limita a los caracteres de rango \['Z' .. 'A ', 'a' .. 'z', '0 '.. '9',, '.' '-','_'\], y no distingue entre mayúsculas y minúsculas. Si el decodificador es compatible con la codificación dada, la función debe establecer al menos el miembro `Decode` del registro suministrado y devolver *True*. Cumplimentar otros miembros de `Decoder` es opcional. | |
| 26 | + | ||
| 27 | + | #### Cleanup | |
| 28 | + | ||
| 29 | + | ``` pascal | |
| 30 | + | procedure Cleanup(Context: Pointer); stdcall; | |
| 31 | + | ``` | |
| 32 | + | ||
| 33 | + | Si `GetDecoder` establece el miembro `Decoder.Cleanup`, se llamará por el lector de una vez, después de la transformación de la entidad actual esté acabada. Como sugiere el nombre, el decodificador debe liberar todos los recursos asignados. | |
| 34 | + | ||
| 35 | + | El valor de `Decoder.Context` se pasa a los procedimientos `Decode` y `Cleanup` cada vez que es llamado. El lector no da ningún significado a este valor. | |
| 36 | + | ||
| 37 | + | #### Decode | |
| 38 | + | ||
| 39 | + | ``` pascal | |
| 40 | + | function Decode(Context: Pointer; InBuf: PChar; var InCnt: Cardinal; OutBuf: PWideChar; var OutCnt: Cardinal): Integer; stdcall; | |
| 41 | + | ``` | |
| 42 | + | ||
| 43 | + | La función `Decode` hace el trabajo principal. Convierte los datos de entrada apuntados por `inbuf` a UTF-16 formato de boble byte de la plataforma actual y la pone en `outbuf`. El tamaño del espacio de entrada se muestra en `InCnt`, el espacio disponible en el espacio de salida se encuentra en `OutCnt`. | |
| 44 | + | ||
| 45 | + | Una diferencia importante a destacar es que `InCnt` se da en **bytes**, mientras que `OutCnt` está en **WideChars**. | |
| 46 | + | ||
| 47 | + | La función debe decrementar `InCnt` y `OutCnt` de acuerdo a la cantidad de datos procesados. Cada carácter procesados disminuye `OutCnt` en una unidad (o dos en caso de que el sustituto escrito sea doble), la cantidad a disminuir de `InCnt` depende de la codificación real. | |
| 48 | + | ||
| 49 | + | No debe hacerse níngun presunción sobre el tamaño inicial de la memoria de trabajo: por ejemplo, el lector puede llamar al decodificador con sólo unos pocos bytes en la memoria de entrada. La función decodificador debe volver cero para indicar que nada se ha procesado, y el lector pondrá más datos en la entrada y llamará de nuevo al decodificador. | |
| 50 | + | ||
| 51 | + | La función debe devolver un valor positivo si ha procesado algo, cero si no (por ejemplo, porque no hay espacio disponible en cualquiera de las memorias de entrada o de salida), y negativo en el caso de datos de entrada con secuencias ilegales. En el futuro, se intentará categorizar los errores de decodificación, pero en la actualidad cualquier valor de retorno negativo simplemente cancela la lectura con el mensaje 'Decoding error'. | |
| 52 | + | ||
| 53 | + | Aún en el caso de error en los datos de entrada el decodificador debe disminuir `OutCnt` para reflejar el número de caracteres procesado con éxito. Esto será utilizado por el lector para ofrecer información de localización en el mensaje de error de excepción. | |
| 54 | + | ||
| 55 | + | ### Ejemplo de decodificador | |
| 56 | + | ||
| 57 | + | Lo que sigue es un ejemplo de una unidad que decodifica cp866. Este decodificador no tiene estado, por lo que no utiliza los miembros `Cleanup` y `Context`. Este ejemplo es muy fácil de modificar para manejar cualquier codificación similar de un solo byte con sólo reemplazar la tabla de conversión. | |
| 58 | + | ||
| 59 | + | ``` pascal | |
| 60 | + | unit xmlcp866; | |
| 61 | + | ||
| 62 | + | interface | |
| 63 | + | ||
| 64 | + | implementation | |
| 65 | + | ||
| 66 | + | uses | |
| 67 | + | SysUtils, xmlread; | |
| 68 | + | ||
| 69 | + | const | |
| 70 | + | cp866table: array[#128..#255] of WideChar=( | |
| 71 | + | #$0410, #$0411, #$0412, #$0413, #$0414, #$0415, #$0416, #$0417, | |
| 72 | + | #$0418, #$0419, #$041A, #$041B, #$041C, #$041D, #$041E, #$041F, | |
| 73 | + | #$0420, #$0421, #$0422, #$0423, #$0424, #$0425, #$0426, #$0427, | |
| 74 | + | #$0428, #$0429, #$042A, #$042B, #$042C, #$042D, #$042E, #$042F, | |
| 75 | + | #$0430, #$0431, #$0432, #$0433, #$0434, #$0435, #$0436, #$0437, | |
| 76 | + | #$0438, #$0439, #$043A, #$043B, #$043C, #$043D, #$043E, #$043F, | |
| 77 | + | #$2591, #$2592, #$2593, #$2502, #$2524, #$2561, #$2562, #$2556, | |
| 78 | + | #$2555, #$2563, #$2551, #$2557, #$255D, #$255C, #$255B, #$2510, | |
| 79 | + | #$2514, #$2534, #$252C, #$251C, #$2500, #$253C, #$255E, #$255F, | |
| 80 | + | #$255A, #$2554, #$2569, #$2566, #$2560, #$2550, #$256C, #$2567, | |
| 81 | + | #$2568, #$2564, #$2565, #$2559, #$2558, #$2552, #$2553, #$256B, | |
| 82 | + | #$256A, #$2518, #$250C, #$2588, #$2584, #$258C, #$2590, #$2580, | |
| 83 | + | #$0440, #$0441, #$0442, #$0443, #$0444, #$0445, #$0446, #$0447, | |
| 84 | + | #$0448, #$0449, #$044A, #$044B, #$044C, #$044D, #$044E, #$044F, | |
| 85 | + | #$0401, #$0451, #$0404, #$0454, #$0407, #$0457, #$040E, #$045E, | |
| 86 | + | #$00B0, #$2219, #$00B7, #$221A, #$2116, #$00A4, #$25A0, #$00A0); | |
| 87 | + | ||
| 88 | + | function cp866Decode(Context: Pointer; InBuf: PChar; var InCnt: Cardinal; OutBuf: PWideChar; | |
| 89 | + | var OutCnt: Cardinal): Integer; stdcall; | |
| 90 | + | var | |
| 91 | + | I: Integer; | |
| 92 | + | cnt: Cardinal; | |
| 93 | + | begin | |
| 94 | + | cnt := OutCnt; // num of widechars | |
| 95 | + | if cnt > InCnt then | |
| 96 | + | cnt := InCnt; | |
| 97 | + | for I := 0 to cnt-1 do | |
| 98 | + | begin | |
| 99 | + | if InBuf[I] < #128 then | |
| 100 | + | OutBuf[I] := WideChar(ord(InBuf[I])) | |
| 101 | + | else | |
| 102 | + | OutBuf[I] := cp866table[InBuf[I]]; | |
| 103 | + | end; | |
| 104 | + | Dec(InCnt, cnt); | |
| 105 | + | Dec(OutCnt, cnt); | |
| 106 | + | Result := cnt; | |
| 107 | + | end; | |
| 108 | + | ||
| 109 | + | function GetCP866Decoder(const AEncoding: string; out Decoder: TDecoder): Boolean; stdcall; | |
| 110 | + | begin | |
| 111 | + | // Most encodings typically have one or more alias names. | |
| 112 | + | if SameText(AEncoding, 'IBM866') or | |
| 113 | + | SameText(AEncoding, 'cp866') or | |
| 114 | + | SameText(AEncoding, '866') or | |
| 115 | + | SameText(AEncoding, 'csIBM866') then | |
| 116 | + | begin | |
| 117 | + | Decoder.Decode := @cp866Decode; | |
| 118 | + | Decoder.Cleanup := nil; | |
| 119 | + | Decoder.Context := nil; | |
| 120 | + | Result := True; | |
| 121 | + | end | |
| 122 | + | else | |
| 123 | + | Result := False; | |
| 124 | + | end; | |
| 125 | + | ||
| 126 | + | initialization | |
| 127 | + | RegisterDecoder(@GetCP866Decoder); | |
| 128 | + | end. | |
| 129 | + | ``` | |
| 130 | + | ||
| 131 | + | ## Ver también | |
| 132 | + | ||
| 133 | + | - [[XML Tutorial/es]] | |
| 134 | + | ||
| 135 | + | --- | |
| 136 | + | *From the Free Pascal wiki, page "XML Decoders/es", as it stood on 2020-03-03 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* | |
| 137 | + | Category: Castellano | |
| 138 | + | Category: Español |
