JavaScript Python PHP
import * as __biblioteca0 from "saxes";
import * as __biblioteca1 from "yaml";
function executar(input = '{"usuario":{"@attributes":{"id":"00123"},"nome":"João"}}', root = 'root') {
const SaxesParser = __biblioteca0["SaxesParser"];
const { parseJsonCompatible: parseJsonCompatible } = (() => {
const LineCounter = __biblioteca1["LineCounter"];
const parseDocument = __biblioteca1["parseDocument"];
const isAlias = __biblioteca1["isAlias"];
const isScalar = __biblioteca1["isScalar"];
const isSeq = __biblioteca1["isSeq"];
const isMap = __biblioteca1["isMap"];
const SAFE_TAGS = new Set(['str', 'bool', 'null', 'int', 'float', 'map', 'seq'].map(tag => `tag:yaml.org,2002:${tag}`));
function parseJsonCompatible(input, format, onObjectKeys) {
if (!input.trim())
throw new Error(`Informe um documento ${format}.`);
if (input.length > 1000000)
throw new Error('A entrada excede o limite de 1 milhão de caracteres.');
if (format === 'JSON') {
// Syntax check only: do not use the rounded numeric values from JSON.parse.
try {
JSON.parse(input);
}
catch (cause) {
throw new Error(`JSON inválido: ${cause instanceof Error ? cause.message : 'erro de sintaxe'}`);
}
}
const lines = new LineCounter();
const doc = parseDocument(input, { version: '1.2', schema: format === 'JSON' ? 'json' : 'core', intAsBigInt: true, uniqueKeys: true, lineCounter: lines, prettyErrors: true, resolveKnownTags: false });
const issue = doc.errors[0] ?? doc.warnings[0];
if (issue)
throw new Error(`${format} inválido (${issue.code}): ${issue.message}`);
if (doc.directives?.yaml.version !== '1.2')
throw new Error('Somente YAML 1.2 é aceito para preservar os tipos de JSON.');
let count = 0;
function fail(message, node) {
const offset = node?.range?.[0];
const position = offset === undefined ? '' : (() => { const { line, col } = lines.linePos(offset); return ` (linha ${line}, coluna ${col})`; })();
throw new Error(message + position);
}
function convert(node, depth = 0) {
if (++count > 100000 || depth > 100)
fail('Documento muito complexo: limite de 100 níveis ou 100 mil nós.', node);
if (!node)
return null;
if (isAlias(node))
fail('Aliases YAML não são aceitos: JSON não preserva referências ou ciclos.', node);
if (node.tag && !SAFE_TAGS.has(node.tag))
fail(`Tag não permitida: ${node.tag}.`, node);
if (isScalar(node)) {
const value = node.value;
if (typeof value === 'bigint') {
if (value === BigInt(0) && node.source?.startsWith('-'))
fail('JSON de saída não preserva o sinal de zero negativo. Use 0 ou uma string.', node);
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER))
fail('Inteiro fora do intervalo seguro de JSON/JavaScript. Use uma string entre aspas para preservar todos os dígitos.', node);
return Number(value);
}
if (typeof value === 'number') {
if (!Number.isFinite(value))
fail('JSON não representa NaN ou infinito.', node);
if (Number.isInteger(value) && !Number.isSafeInteger(value))
fail('Número inteiro fora do intervalo seguro. Use uma string entre aspas para preservar a precisão.', node);
if (value === 0 && /[1-9]/.test((node.source ?? '').split(/[eE]/)[0]))
fail('Número pequeno demais para a precisão de JavaScript. Use uma string entre aspas.', node);
if (Object.is(value, -0))
fail('JSON de saída não preserva o sinal de zero negativo. Use 0 ou uma string.', node);
return value;
}
if (value === null || typeof value === 'string' || typeof value === 'boolean')
return value;
fail('Valor não representável em JSON.', node);
}
if (isSeq(node))
return node.items.map(item => convert(item, depth + 1));
if (isMap(node)) {
const result = Object.create(null);
const keys = [];
for (const pair of node.items) {
if (!isScalar(pair.key) || typeof pair.key.value !== 'string')
fail('Chaves de objetos devem ser strings; chaves numéricas, booleanas ou complexas não são preservadas em JSON.', pair.key);
const key = pair.key.value;
if (format === 'YAML' && key === '<<' && pair.key.type === 'PLAIN')
fail('Chaves de merge YAML (<<) não são aceitas.', pair.key);
if (Object.hasOwn(result, key))
fail(`Chave duplicada: ${key}.`, pair.key);
keys.push(key);
result[key] = convert(pair.value, depth + 1);
}
onObjectKeys?.(result, keys);
return result;
}
fail('Estrutura não representável em JSON.', node);
}
if (!doc.contents)
throw new Error('Informe um documento com um valor; use null para um valor nulo.');
return convert(doc.contents);
}
return { parseJsonCompatible: parseJsonCompatible };
})();
function xmlCharacters(value) {
for (const character of value) {
const cp = character.codePointAt(0);
if (!(cp === 9 || cp === 10 || cp === 13 || (cp >= 32 && cp <= 0xD7FF) || (cp >= 0xE000 && cp <= 0xFFFD) || (cp >= 0x10000 && cp <= 0x10FFFF)))
throw new Error('Caractere não permitido pelo XML 1.0.');
}
}
function validName(name, attribute = false) {
if (!name || name.includes(':') || (attribute && name === 'xmlns'))
throw new Error(`Nome XML inválido ou namespace não suportado: "${name}".`);
let matched = false;
const parser = new SaxesParser();
parser.on('opentag', tag => { matched = tag.name === name && Object.keys(tag.attributes).length === 0; });
try {
parser.write(`<${name}/>`).close();
}
catch {
throw new Error(`Nome XML inválido: "${name}".`);
}
if (!matched)
throw new Error(`Nome XML inválido: "${name}".`);
}
function escapeXml(value, attribute = false) {
xmlCharacters(value);
const escaped = value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\r/g, ' ');
return attribute ? escaped.replace(/"/g, '"').replace(/\t/g, '	').replace(/\n/g, ' ') : escaped;
}
function scalar(value) {
if (value === null || typeof value === 'object')
throw new Error('Null, objetos e listas não podem ser usados como texto ou atributo XML.');
return String(value);
}
function jsonToXml(input, root = 'root') {
validName(root);
const orders = new WeakMap();
const data = parseJsonCompatible(input, 'JSON', (object, keys) => orders.set(object, keys));
function element(name, value) {
validName(name);
if (value === null)
throw new Error(`Elemento "${name}": null não tem representação suportada; use string vazia.`);
if (Array.isArray(value))
throw new Error('Listas só são aceitas como propriedades de elementos filhos, não na raiz ou dentro de listas.');
if (typeof value !== 'object')
return `<${name}>${escapeXml(scalar(value))}</${name}>`;
const keys = orders.get(value) ?? Object.keys(value);
if (!keys.length)
throw new Error(`Elemento "${name}": objeto vazio não tem representação distinta de string vazia.`);
let attributes = '';
if (Object.hasOwn(value, '@attributes')) {
const bag = value['@attributes'];
if (bag === null || typeof bag !== 'object' || Array.isArray(bag) || !Object.keys(bag).length)
throw new Error('@attributes deve ser um objeto não vazio de valores escalares.');
for (const key of orders.get(bag) ?? Object.keys(bag)) {
validName(key, true);
attributes += ` ${key}="${escapeXml(scalar(bag[key]), true)}"`;
}
}
const children = keys.filter(key => key !== '@attributes' && key !== '#text');
if (children.length && Object.hasOwn(value, '#text'))
throw new Error('Conteúdo misto (#text junto a elementos filhos) não é suportado.');
let body = Object.hasOwn(value, '#text') ? escapeXml(scalar(value['#text'])) : '';
for (const key of children) {
const child = value[key];
if (Array.isArray(child)) {
if (!child.length)
throw new Error(`Elemento "${key}": lista vazia não tem representação suportada.`);
body += child.map(item => element(key, item)).join('');
}
else
body += element(key, child);
}
return `<${name}${attributes}>${body}</${name}>`;
}
return element(root, data);
}
return jsonToXml(input, root);
}
import json
import math
from xml.parsers import expat
def executar(input='{"usuario":{"@attributes":{"id":"00123"},"nome":"João"}}', root="root"):
def read(text):
if not text.strip() or len(text.encode("utf-16-le", errors="surrogatepass")) // 2 > 1000000:
raise ValueError("Informe JSON com até 1 milhão de caracteres.")
def pairs(items):
result = {}
for key, value in items:
if key in result: raise ValueError("Chave duplicada: " + key)
result[key] = value
return result
def number(token):
value = float(token) if "." in token or "e" in token.lower() else int(token)
if not math.isfinite(value) or (value == 0 and (token.startswith("-") or any(c in "123456789" for c in token.lower().split("e")[0]))) or (value % 1 == 0 and abs(value) > 9007199254740991):
raise ValueError("Número não preservável; use uma string para preservar os dígitos.")
return value
def reject(token): raise ValueError("Constante JSON inválida: " + token)
value = json.loads(text, object_pairs_hook=pairs, parse_int=number, parse_float=number, parse_constant=reject)
count = 0
def walk(item, depth=0):
nonlocal count
count += 1
if count > 100000 or depth > 100: raise ValueError("Limite de 100 níveis ou 100 mil nós.")
if isinstance(item, dict):
for child in item.values(): walk(child, depth + 1)
elif isinstance(item, list):
for child in item: walk(child, depth + 1)
walk(value)
return value
def scalar(value):
if value is None: return "null"
if value is True: return "true"
if value is False: return "false"
if isinstance(value, float):
if value == int(value): return str(int(value))
text = repr(value)
if "e" in text:
coefficient, power = text.split("e")
exponent = int(power)
if -6 <= exponent < 21:
negative = coefficient.startswith("-")
coefficient = coefficient.lstrip("-")
digits = coefficient.replace(".", "")
point = coefficient.find(".") if "." in coefficient else len(coefficient)
point += exponent
return ("-" if negative else "") + ("0." + "0" * -point + digits if point <= 0 else digits + "0" * (point - len(digits)) if point >= len(digits) else digits[:point] + "." + digits[point:])
return coefficient + "e" + ("+" if exponent >= 0 else "-") + str(abs(exponent))
return text
return str(value)
def name(value, attribute=False):
if not value or ":" in value or (attribute and value == "xmlns"): raise ValueError("Nome XML inválido ou namespace não suportado.")
parser = expat.ParserCreate()
def opened(key, attributes):
if key != value or attributes: raise ValueError("Nome XML inválido.")
parser.StartElementHandler = opened
try: parser.Parse("<" + value + "/>", True)
except expat.ExpatError as error: raise ValueError("Nome XML inválido: " + value) from error
def escape(value, attribute=False):
if value is None or isinstance(value, (dict, list)): raise ValueError("Texto/atributo deve ser escalar, sem null.")
text = scalar(value)
for c in text:
cp = ord(c)
if not (cp in (9, 10, 13) or 32 <= cp <= 0xD7FF or 0xE000 <= cp <= 0xFFFD or 0x10000 <= cp <= 0x10FFFF): raise ValueError("Caractere não permitido pelo XML 1.0.")
text = text.replace("&", "&").replace("<", "<").replace(">", ">").replace("\r", " ")
return text.replace('"', """).replace("\t", "	").replace("\n", " ") if attribute else text
def element(key, value):
name(key)
if value is None or isinstance(value, list): raise ValueError("Null e listas na raiz/dentro de listas não têm representação suportada.")
if not isinstance(value, dict): return f"<{key}>" + escape(value) + f"</{key}>"
if not value: raise ValueError("Objeto vazio não tem representação distinta de string vazia.")
attributes = ""
if "@attributes" in value:
bag = value["@attributes"]
if not isinstance(bag, dict) or not bag: raise ValueError("@attributes deve ser objeto não vazio.")
for attribute, item in bag.items():
name(attribute, True)
attributes += " " + attribute + '="' + escape(item, True) + '"'
children = [key for key in value if key not in ("@attributes", "#text")]
if children and "#text" in value: raise ValueError("Conteúdo misto não é suportado.")
body = escape(value["#text"]) if "#text" in value else ""
for child in children:
items = value[child] if isinstance(value[child], list) else [value[child]]
if not items: raise ValueError("Lista vazia não tem representação suportada.")
body += "".join(element(child, item) for item in items)
return f"<{key}{attributes}>{body}</{key}>"
return element(root, read(input))
<?php
function executar($input = '{"usuario":{"@attributes":{"id":"00123"},"nome":"João"}}', $root = 'root') {
$read = function ($text) {
if (trim($text) === '' || !mb_check_encoding($text, 'UTF-8') || strlen(mb_convert_encoding($text, 'UTF-16LE', 'UTF-8')) / 2 > 1000000) throw new InvalidArgumentException('Informe JSON válido com até 1 milhão de caracteres.');
json_decode($text, false, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
$stack = [];
for ($i = 0; $i < strlen($text); $i++) {
$ch = $text[$i];
if ($ch === '{' || $ch === '[') { $stack[] = ['keys'=>[]]; if (count($stack) > 101) throw new InvalidArgumentException('Limite de profundidade.'); }
elseif ($ch === '}' || $ch === ']') array_pop($stack);
elseif ($ch === '"') {
$start = $i;
while (++$i < strlen($text)) { if ($text[$i] === '\\') $i++; elseif ($text[$i] === '"') break; }
$look = $i + 1;
while ($look < strlen($text) && str_contains(" \r\n\t", $text[$look])) $look++;
if (($text[$look] ?? '') === ':') {
$key = json_decode(substr($text, $start, $i - $start + 1), false, 512, JSON_THROW_ON_ERROR);
$index = count($stack) - 1;
if (array_key_exists($key, $stack[$index]['keys'])) throw new InvalidArgumentException('Chave duplicada: '.$key);
$stack[$index]['keys'][$key] = true;
}
} elseif ($ch === '-' || ctype_digit($ch)) {
preg_match('/\G-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/', $text, $match, 0, $i);
$token = $match[0]; $value = (float)$token;
if (!is_finite($value) || ($value == 0 && (str_starts_with($token, '-') || preg_match('/[1-9]/', explode('e', strtolower($token))[0]))) || (floor($value) === $value && abs($value) > 9007199254740991)) throw new InvalidArgumentException('Número não preservável; use uma string.');
$i += strlen($token) - 1;
}
}
$value = json_decode($text, false, 512, JSON_THROW_ON_ERROR);
$count = 0;
$walk = function ($node, $depth = 0) use (&$walk, &$count) {
if (++$count > 100000 || $depth > 100) throw new InvalidArgumentException('Limite de 100 níveis ou 100 mil nós.');
if (is_object($node) || is_array($node)) foreach ($node as $child) $walk($child, $depth + 1);
};
$walk($value);
return $value;
};
$dump = fn($value) => preg_replace_callback('/^( +)/m', fn($match) => str_repeat(' ', strlen($match[1]) / 2), json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
$scalar = fn($value) => is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$name = function ($value, $attribute = false) {
if ($value === '' || str_contains($value, ':') || ($attribute && $value === 'xmlns')) throw new InvalidArgumentException('Nome inválido ou namespace não suportado.');
try { (new DOMDocument('1.0', 'UTF-8'))->createElement($value); }
catch (DOMException $error) { throw new InvalidArgumentException('Nome XML inválido: '.$value, 0, $error); }
};
$escape = function ($value, $attribute = false) use ($scalar) {
if ($value === null || is_object($value) || is_array($value)) throw new InvalidArgumentException('Texto/atributo deve ser escalar, sem null.');
$text = $scalar($value);
if (preg_match('/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', $text)) throw new InvalidArgumentException('Caractere não permitido pelo XML 1.0.');
$text = str_replace(["&", "<", ">", "\r"], ['&', '<', '>', ' '], $text);
return $attribute ? str_replace(['"', "\t", "\n"], ['"', '	', ' '], $text) : $text;
};
$element = function ($key, $value) use (&$element, $name, $escape) {
$name($key);
if ($value === null || is_array($value)) throw new InvalidArgumentException('Null e listas na raiz/dentro de listas não são suportados.');
if (!$value instanceof stdClass) return '<'.$key.'>'.$escape($value).'</'.$key.'>';
if (!(array)$value) throw new InvalidArgumentException('Objeto vazio não tem representação distinta de string vazia.');
$attributes = '';
if (property_exists($value, '@attributes')) {
$bag = $value->{'@attributes'};
if (!$bag instanceof stdClass || !(array)$bag) throw new InvalidArgumentException('@attributes deve ser objeto não vazio.');
foreach ($bag as $attribute => $item) { $name((string)$attribute, true); $attributes .= ' '.$attribute.'="'.$escape($item, true).'"'; }
}
$children = array_values(array_filter(array_keys((array)$value), fn($key) => $key !== '@attributes' && $key !== '#text'));
if ($children && property_exists($value, '#text')) throw new InvalidArgumentException('Conteúdo misto não é suportado.');
$body = property_exists($value, '#text') ? $escape($value->{'#text'}) : '';
foreach ($children as $child) {
$items = is_array($value->{$child}) ? $value->{$child} : [$value->{$child}];
if (!$items) throw new InvalidArgumentException('Lista vazia não tem representação suportada.');
foreach ($items as $item) $body .= $element((string)$child, $item);
}
return '<'.$key.$attributes.'>'.$body.'</'.$key.'>';
};
return $element($root, $read($input));
}