1

estoy intentando acceder al servidor sql para que me muestre por pantalla "Noticias" en una tabla XML usando ajax, javascript y php. El problema me lo esta dando en el fichero getNoticias.php, diciéndome que no puede leer o que es valor null el tag "noti".

getNoticias.php:

  <?php

// Configuración BASE DE DATOS MYSQL
$servidor  = "localhost";
$basedatos = "senderismo";
$usuario   = "root";
$password  = "";

// Creamos la conexión al servidor.
$conexion = mysqli_connect($servidor, $usuario, $password,$basedatos) or die(mysqli_error($conexion));
mysqli_query($conexion,"utf8");

// Consulta SQL para obtener los datos de los centros.
$sql = "SELECT * FROM noticias";
$resultados = mysqli_query($conexion,$sql);

$XML ='<?xml version="1.0" encoding="UTF-8"?>';
$XML .='<datos>';

while ($fila = mysqli_fetch_array($resultados)) {
    $XML .='<noti>';
        $XML .='<idnot>'.$fila["idnoticia"].'</idnot>';
        $XML .='<tit>'.$fila["titulo"].'</tit>';
        $XML .='<descri>'.$fila["descripcion"].'</descri>';
        $XML .='<aut>'.$fila["autor"].'</aut>';
        $XML .='<fech>'.$fila["fecha"].'</fech>';
        $XML .='<image>'.$fila["imagen"].'</image>';
    $XML .='</noti>';
}

$XML .='</datos>';

// Cabecera de respuesta indicando que el contenido de la respuesta es XML
header("Content-Type: text/xml");
// Para que el navegador no haga cache de los datos devueltos por la página PHP.
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

echo $XML;

mysqli_close($conexion);
?>

Index.js

    function pedirListado() 
{
            // Instanciar objeto Ajax
            var oAjax = instanciarXHR();

            //Configurar la llamada --> Asincrono por defecto
            oAjax.open("GET", "php/getNoticias.php");

            //Asociar manejador de evento de la respuesta
            oAjax.addEventListener("readystatechange", procesoRespuestalistadoNoticiasXML, false);

            //Hacer la llamada
            oAjax.send(null);
            
}
    
        function procesoRespuestalistadoNoticiasXML() {
            var oAjax = this;

            // Proceso la respuesta cuando llega
            if (oAjax.readyState == 4 && oAjax.status == 200) {
                console.log(oAjax.responseText);
                var oXML = oAjax.responseXML; // Recojo un objeto XML

                construirListado(oXML);
            }
        }
        
            function construirListado(oXML) {
            // Crear tabla
            var oTabla = document.createElement("table");
            oTabla.border = "1";
            var oTHead = oTabla.createTHead();
            var oFila = oTHead.insertRow(-1);
            var oTH = document.createElement("TH");
            oTH.textContent = "idnoti";
            oFila.appendChild(oTH);
            
            oTH = document.createElement("TH");
            oTH.textContent = "tit";
            oFila.appendChild(oTH);

            oTH = document.createElement("TH");
            oTH.textContent = "descri";
            oFila.appendChild(oTH);

            oTH = document.createElement("TH");
            oTH.textContent = "aut";
            oFila.appendChild(oTH);
            
            oTH = document.createElement("TH");
            oTH.textContent = "fech";
            oFila.appendChild(oTH);
            
            oTH = document.createElement("TH");
            oTH.textContent = "image";
            oFila.appendChild(oTH);


            var oTBody = oTabla.createTBody();


            var oNoticias = oXML.querySelectorAll("noti");
            for (var i = 0; i < oNoticias.length; i++) {
                oFila = oTBody.insertRow(-1);

                var oCelda = oFila.insertCell(-1);
                oCelda.textContent = oNoticias[i].querySelector("idnoti").textContent;

                oCelda = oFila.insertCell(-1);
                oCelda.textContent = (oNoticias[i].querySelector("tit").textContent);

                oCelda = oFila.insertCell(-1);
                oCelda.textContent = (oNoticias[i].querySelector("descri").textContent);
            
                oCelda = oFila.insertCell(-1);
                oCelda.textContent = (oNoticias[i].querySelector("aut").textContent);

                oCelda = oFila.insertCell(-1);
                oCelda.textContent = (oNoticias[i].querySelector("fech").textContent);
                
                oCelda = oFila.insertCell(-1);
                oCelda.textContent = (oNoticias[i].querySelector("image").textContent);

            }
            document.querySelector("#listado").innerHTML = "";
            document.querySelector("#listado").appendChild(oTabla);
        }
        
        
        function instanciarXHR() {
            var xhttp = null;

            if (window.XMLHttpRequest) {
                xhttp = new XMLHttpRequest();
            } else // code for IE5 and IE6
            {
                xhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }

            return xhttp;
        }

Aparentemente veo que el código esta correctamente, en la base de datos tengo 6 tablas que son las que especifico en el código php y luego en el index.js creo 6 tablas para cada uno de los elementos.

Pero a la hora de pulsar el botón me dice el siguiente error:

        index.js:80 Uncaught TypeError: Cannot read property 'querySelectorAll' of null
at construirListado (index.js:80)
at XMLHttpRequest.procesoRespuestalistadoNoticiasXML (index.js:42)

Los nombres de las tablas están bien, en minúscula, la base de datos bien definida y ya no se donde tocar mas. A ver si podéis ayudarme gracias.

Los datos si los manda ya que aparecen por console: ejemplo

John Doe
  • 73
  • 7
  • ¿Verificaste que `oXML` es realmente un XML válido? – A. Cedano Apr 19 '21 at 12:58
  • No, a que te refieres? – John Doe Apr 19 '21 at 13:05
  • Me refiero a que muestres en consola la respuesta para verificar si está viniendo y si es un XML válido, poniendo algo así `console.log(oAjax.response, oAjax.responseXML);` en la parte donde recibes la respuesta del servidor y verificando lo que se imprime en consola. – A. Cedano Apr 19 '21 at 13:09
  • Vale he actualizado la pregunta con una captura y si manda datos. – John Doe Apr 19 '21 at 15:34
  • Pero ese XML no es válido, todos esos caracteres inspector que ves estarían rompiendo tu XML. Es evidente que tienes un problema con la codificación en algún lado y tienes que resolverlo. Puede ser porque no le pusiste el charset adecuado en el header del Content-Type, o porque no lo indicase en la conexión a la base de datos o en PHP. [Revisa esta respuesta](https://es.stackoverflow.com/a/59510/29967) que da algunas pautas sobre este problema. – A. Cedano Apr 19 '21 at 17:43
  • todos esos caracteres corresponden a una imagen que esta subida en el servidor sql, he probado a quitar el campo imagen y mostrar los demás datos y tampoco me funciona. – John Doe Apr 19 '21 at 17:45
  • No, no es sólo la imagen. Observa los contenidos con texto, a partir de `descri` ya empiezan a aparecer datos con el carácter inspector. Eso rompe tu XML, no podrás generar un XML válido mientras aparezcan caracteres extraños en él y ese caracter aparece porque tienes un problema de codificación en algún lado. – A. Cedano Apr 19 '21 at 17:48
  • Empieza poniendo el header así: **`header("Content-type: text/xml; charset=utf-8");`** Si no funciona tendrás que poner charset en la conexión en la BD, en la configuración de PHP y si no funciona aún así tendrás que verificar en la BD. – A. Cedano Apr 19 '21 at 17:50
  • Eso lo tengo puesto, lo que aparece como inspector son tildes, eso puede dar problemas? – John Doe Apr 19 '21 at 18:03
  • Claro que da problemas. Ese XML no validará nunca con los caracteres inspector. Es como si no se estuviera produciendo un XML, porque aunque tengas bien todas las etiquetas el inspector rompe el XML. Si con esto no se resuelve: `header("Content-type: text/xml; charset=utf-8");` pon el mismo charset cuando creas la conexión mysqli y si no funciona, pon utf-8 también en el contexto de PHP. Y si no revisa los datos en la BD. Si allí tienen inspector tendrás que cambiar la codificación de la tabla/columna y quizá corregir los datos. En ese caso tendrás antes que hacer un backup de la tabla. – A. Cedano Apr 19 '21 at 18:09
  • Me acaba de funcionar, ya me muestra los datos, en el caso de que quisiera que me mostrara la imagen, que debería hacer? – John Doe Apr 19 '21 at 18:35
  • Puede que tengas que convertirla con `base64_encode($fila['imagen'])` o de otro modo. – A. Cedano Apr 19 '21 at 18:51
  • vale iré probando, pon tu respuesta y la doy como válida, gracias! – John Doe Apr 19 '21 at 18:54

1 Answers1

2

Considera siempre hacer una depuración con los datos con los que quieres trabajar. En este caso, si oXML está dando problemas conviene depurar ese elemento, escribiendo en consola el código que lo origina y revisando la consola:

console.log(oAjax.response, oAjax.responseXML);

En efecto, esta depuración ha revelado que en el contenido venían datos con el carácter inspector. Cuando este carácter aparece es un claro indicativo de un problema con la codificación, lo cual estaría produciendo un XML inválido, que hará fallar cualquier tipo de manejo basado en XML.

Para resolver este problema de entrada puedes indicar la codificación tanto en el header como en la conexión (esto conviene hacerlo siempre). Si aún así no funciona tendrás que verificar si el entorno PHP no tiene la codificación correcta y si no tendrás que verificar los datos en sí mismo en la base de datos. Si allí aparecen con el carácter inspector tendrás que pensar en normalizar en la base de datos, dando a los datos una codificación adecuada (es altamente recomendable hacer un backup de la base de datos si vas a cambiar configuraciones como la codificación de los datos). Finalmente, si guardas estos datos en la BD desde archivos externos tendrás que revisar, para un futuro, la configuración de esos archivos.

Aplicando lo que hemos dicho:

Configuramos la codificación en la conexión:

mysqli_query($conexion,"utf8");

Y, aunque ya en la definición del XML has indicado una codificación: $XML ='<?xml version="1.0" encoding="UTF-8"?>';, conviene también ponerlo siempre en el header:

header("Content-type: text/xml; charset=utf-8");

Para las otras etapas de verificación puedes ver esta respuesta, donde se aborda el problema con mayor amplitud.

En cuanto a la imagen, puede que necesites convertirla, con base64_encode o de otro modo:

    $XML .='<image>'.base64_encode($fila["imagen"]).'</image>';
A. Cedano
  • 86,578
  • 19
  • 122
  • 221