Calculando HASH
Como calcular corretamente o hash
Assumindo um objeto DOM representando a requisição SOAP e um nome de tag de mensagem TISS válidos. Busque o primeiro nó da mensagem no documento XML que corresponda ao nome fornecido, considerando qualquer namespace.
Ex.: getElementsByTagNameNS('*', nodeName)- Se o nó não for encontrado, considere que houve um erro/exceção.
- Extraia todo o conteúdo textual dos nós descendentes do nó alvo.
- Para cada nó filho:
- Se for um elemento com filhos, aplique a mesma lógica para cada filho.
- Senão, se for um nó de texto inclua seu valor textual, removendo espaços em branco extras (início e fim).
- Concatene todos os textos extraídos em uma única string e retorne.
- Concatene todos os textos extraídos em uma única string e retorne.
- Para cada nó filho:
- Calcule o hash MD5 da string final, representando em hexadecimal (preferencialmente minúsculas mas webservice aceitará a string como case insensitive).
- Crie um elemento com a tag
<hash>, o conteúdo deve ser o MD5. - Adicione a tag como último filho da tag de mensagem.
- Retorne o documento XML atualizado.
Exemplo em NodeJS
import {createHash} from 'node:crypto';import { DOMParser, XMLSerializer } from 'xmldom';
/** * Extrai o texto de todos os nós filhos de um nó, em qualquer profundidade. * * @param {Node} node * O nó XML a ser processado. * @returns {string} * O texto concatenado dos nós filhos. */function getTextContent(node) { let text = ''; for (const child of Array.from(node.childNodes)) { if (child.nodeType === 3) { text += child.nodeValue.trim(); } else if (child.nodeType === 1) { text += getTextContent(child); } } return text;}
/** * Calcula o HASH MD5 do conteúdo de um nó especificado e adiciona a tag <hash>. * * @param {Document} xmlDoc * O documento XML parseado. * @param {string} nodeName * O nome do nó a processar. * @param {string} [charset='utf-8'] * O charset para codificação (ex.: 'utf-8', 'latin1'). * @returns {Document} * O documento XML atualizado com a tag <hash>. * @throws {Error} * Se o documento for inválido ou o nó não for encontrado. */function calcularHash(xmlDoc, nodeName, charset = 'utf-8') { if (!xmlDoc || xmlDoc.getElementsByTagName('parsererror').length > 0) { throw new Error('Documento XML inválido'); } if (!nodeName || typeof nodeName !== 'string') { throw new Error('Nome do nó inválido'); } const targetNode = xmlDoc.getElementsByTagNameNS('*', nodeName)[0]; if (!targetNode) { throw new Error(`Nó <${nodeName}> não encontrado`); } const conteudo = getTextContent(targetNode); console.log('Conteúdo', conteudo); const hashMd5 = createHash('md5') .update(Buffer.from(conteudo, charset.toLowerCase())) .digest('hex'); const hashTag = xmlDoc.createElement('hash'); hashTag.textContent = hashMd5; targetNode.appendChild(hashTag); // Não é necessário, apenas facilita visualização targetNode.appendChild(xmlDoc.createTextNode('\n ')); return xmlDoc;}
// main.jsconst xmlString = `<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <dados> <nome>João Assis</nome> <idade>30</idade> <cidade>São Paulo</cidade> <detalhes> <rua>Avenida Brasil</rua> </detalhes> </dados> </soap:Body></soap:Envelope>`;
async function main() { try { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlString, 'application/xml'); if (xmlDoc.getElementsByTagName('parsererror').length > 0) { throw new Error('Erro ao parsear o XML'); } let charset = 'utf-8'; const prologo = xmlString.match(/encoding=["'](.*?)["']/i); if (prologo && prologo[1]) { charset = prologo[1].toLowerCase(); } const xmlAtualizado = calcularHash(xmlDoc, 'dados', charset); const serializer = new XMLSerializer(); const xmlSerializado = serializer.serializeToString(xmlAtualizado); console.log('XML Atualizado:'); console.log(xmlSerializado); } catch (error) { console.error('Falha na execução:', error.message); }}
main();