* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * \file cfdixml/class/cfdi/CadenaOriginalBuilder.php * \ingroup cfdixml * \brief Clase para generar la cadena original del CFDI usando XSLT */ class CadenaOriginalBuilder { private $xsltPath; private $xsltDoc; private $xsltProcessor; public function __construct($xsltPath) { $this->xsltPath = $xsltPath; $this->initializeXSLT(); } /** * Initializes the XSLT processor and loads the XSLT stylesheet. * * This method sets up the DOMDocument for the XSLT file, loads the XSLT from the specified path, * creates an XSLTProcessor, and imports the stylesheet. It handles potential errors during the process. * * @throws \Exception If there's an error loading the XSLT file or importing the stylesheet. * @return void */ private function initializeXSLT() { try { // Verificar si el archivo es remoto o local if (filter_var($this->xsltPath, FILTER_VALIDATE_URL)) { // Si es una URL, descargamos el contenido $context = stream_context_create([ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, ] ]); $xsltContent = file_get_contents($this->xsltPath, false, $context); // Modificar la versión del XSLT de 2.0 a 1.0 $xsltContent = preg_replace('/version="2.0"/', 'version="1.0"', $xsltContent); // Crear documento temporal $this->xsltDoc = new \DOMDocument(); $this->xsltDoc->loadXML($xsltContent); } else { // Si es local, cargar directamente $this->xsltDoc = new \DOMDocument(); $xsltContent = file_get_contents($this->xsltPath); $xsltContent = preg_replace('/version="2.0"/', 'version="1.0"', $xsltContent); $this->xsltDoc->loadXML($xsltContent); } // Crear el procesador XSLT $this->xsltProcessor = new \XSLTProcessor(); // Suprimir warnings durante la importación libxml_use_internal_errors(true); $imported = $this->xsltProcessor->importStylesheet($this->xsltDoc); libxml_use_internal_errors(false); if (!$imported) { throw new \Exception("No se pudo importar la hoja de estilos XSLT"); } } catch (\Exception $e) { throw new \Exception("Error al inicializar XSLT: " . $e->getMessage()); } } /** * Builds the "Cadena Original" from an XML string using XSLT transformation. * * This function takes an XML string, transforms it using the initialized XSLT processor, * and then cleans the resulting string to create the final "Cadena Original". * * @param string $xmlString The XML string to be transformed. * @throws \Exception If there's an error during the XSLT transformation process. * @return string The resulting "Cadena Original" after transformation and cleaning. */ public function buildCadenaOriginal($xmlString) { try { // Crear documento DOM del XML $xmlDoc = new \DOMDocument(); $xmlDoc->loadXML($xmlString); // Realizar la transformación $cadenaOriginal = $this->xsltProcessor->transformToXml($xmlDoc); // Limpiar la cadena original $cadenaOriginal = $this->limpiarCadenaOriginal($cadenaOriginal); return $cadenaOriginal; } catch (\Exception $e) { throw new \Exception("Error en la transformación XSLT: " . $e->getMessage()); } } /** * Cleans and formats the "Cadena Original" string. * * This function removes unwanted characters, trims excess whitespace, * and ensures the string starts and ends with '||' as required for * a valid "Cadena Original" format. * * @param string $cadenaOriginal The raw "Cadena Original" string to be cleaned. * @return string The cleaned and properly formatted "Cadena Original" string. */ private function limpiarCadenaOriginal($cadenaOriginal) { // Eliminar caracteres no deseados y espacios extras $cadenaOriginal = trim($cadenaOriginal); $cadenaOriginal = preg_replace('/\s+/', ' ', $cadenaOriginal); // Verificar que la cadena comience y termine correctamente if (!str_starts_with($cadenaOriginal, '||')) { $cadenaOriginal = '||' . $cadenaOriginal; } if (!str_ends_with($cadenaOriginal, '||')) { $cadenaOriginal .= '||'; } return $cadenaOriginal; } }