4
votes

Obtenez un fichier xml pour rechercher et remplacer du texte. PHP

J'ai besoin de modifier les textes d'un fichier XML en utilisant du code PHP. Ensuite, j'ai créé un code pour:

1- obtenir le fichier

2- remplacer les textes

3- enregistrer le fichier avec un autre nom.

Le problème est que je rencontre des problèmes pour remplacer du texte dans un fichier xml.

Je peux remplacer des chaînes simples mais je ne peux pas remplacer du texte par des caractères comme «

Chemin XML d'origine: http : //www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml

1) Ce code change simplement le texte Inmuebles en xxxxxxxx . Cela fonctionne bien

    $xml_external_path = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml';
$xml = file_get_contents($xml_external_path);

$response = strtr($xml, array(
    '<Publicacion>' => ''
));

$newXml = $response;

$newXml = simplexml_load_string( $newXml );
$newXml->asXml('/home/csainmobiliaria/www/pisos-NEW.xml');

2) Maintenant, si j'utilise ce code pour changer le texte

à J'obtiens une ERREUR 500.
    $xml_external_path = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml';
$xml = file_get_contents($xml_external_path);

$response = strtr($xml, array(
    '<Table Name="Inmuebles">' => '<xxxxxxxx>'
));

$newXml = $response;

$newXml = simplexml_load_string( $newXml );
$newXml->asXml('/home/csainmobiliaria/www/pisos-NEW.xml');

3) De la même manière, si J'utilise ce code pour supprimer le texte Publicacion J'obtiens une ERREUR 500.

    $xml_external_path = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml';
$xml = file_get_contents($xml_external_path);

$response = strtr($xml, array(
    'Inmuebles' => 'xxxxxxxx'
));

$newXml = $response;

$newXml = simplexml_load_string( $newXml );
$newXml->asXml('/home/csainmobiliaria/www/pisos-NEW.xml');

Voici le résultat final I besoin d'obtenir: http://www.csainmobiliaria.com/imagenes/fotos/pisos -OK.xml

Capture:  entrez la description de l'image ici


8 commentaires

à rend la fermeture
invalide et la fermeture inexistante. Utilisez l'analyseur et faites ceci. De plus, lorsque vous obtenez une ERREUR 500 vérifiez vos journaux d'erreurs, cela vous indiquera ce qui ne va pas. S'il ne regarde pas le manuel des fonctions de rapport d'erreurs. L'approche a le même problème. N'utilisez pas de fonctions de chaîne sur des données structurées (CSV, JSON, XML, etc.), utilisez les analyseurs appropriés.


@ user3783243 J'ai bien peur de ne pas savoir ce que sont les «analyseurs». Voulez-vous dire la fonction de recherche de chaîne int?


simplexml est un analyseur. Vous devez apporter le fichier tel quel, le restructurer si nécessaire, puis le sortir. (Il existe également d'autres analyseurs si vous n'aimez pas celui-là)


Possibilité de duplication de Comment analysez-vous et traitez-vous HTML / XML en PHP?


XSLT est un langage de modèle pour ce cas d'utilisation - il transforme un XML en un autre XML, HTML ou texte. PHP a une extension (ext / xsl) pour cela.


@ThW merci. Je comprends que j'ai juste besoin de charger et d'enregistrer le xml avec XSLT au lieu d'utiliser simplexml. J'ai trouvé ça inviqa.com/blog/transforming-xml-php-and-xsl mais il ne montre pas comment l'enregistrer au format XML. Pouvez-vous m'aider s'il vous plaît?


Chaque fois que vous obtenez une erreur 500, la première chose à faire est de trouver votre journal d’erreurs ou d’activer le rapport d’erreurs sur votre serveur de développement. Ensuite, si vous ne comprenez pas ce que vous avez trouvé, vous pouvez nous indiquer le message d'erreur exact que vous recevez . Voir stackoverflow.com/questions/12769982/... et exemple reproductible minimal .


@JPashs le résultat xml n'est pas valide car il doit avoir un élément racine. lorsque vous supprimez , vous créez un xml sans racine et fermez la balise sans l'ouvrir. Tout d'abord, définissez un résultat correct


3 Réponses :


4
votes

Vous pouvez copier le nœud nécessaire au lieu de supprimer les éléments en excès. Par exemple, vous pouvez copier le nœud Inmuebles avec l'aide de SimpleXML:

$path = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml';
$content = file_get_contents($path);
$sourceXML = new SimpleXMLElement($content);

$xslt='<?xml version="1.0" encoding="ISO-8859-1"?>
         <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output method="xml" indent="yes"/>

         <xsl:template match="Table[@Name=\'Inmuebles\']">
             <Inmuebles>
                 <xsl:copy-of select="node()"/>
             </Inmuebles>
         </xsl:template>

         <xsl:template match="Table[@Name=\'Agencias\']"/>
</xsl:stylesheet>';


$xsl = new SimpleXMLElement($xslt);

$processor = new XSLTProcessor;
$processor->importStyleSheet($xsl);
$result = $processor->transformToXML($sourceXML);
$targetXML = new SimpleXMLElement($result);
echo $targetXML->asXML();

De plus, comme @ThW l'a dit dans les commentaires, vous pouvez utiliser XLST , par exemple:

$path = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml';
$content = file_get_contents($path);
$sourceXML = new SimpleXMLElement($content);

$targetXML = new SimpleXMLElement("<Inmuebles></Inmuebles>");

$items = $sourceXML->xpath('Table[@Name=\'Inmuebles\']');
foreach ($items as $item) {
    foreach ($item->Inmueble as $inmueble) {
        $node  = $targetXML->addChild('Inmueble');
        $node->addChild('IdInmobiliariaExterna', $inmueble->IdInmobiliariaExterna);
        $node->addChild('IdPisoExterno', $inmueble->IdPisoExterno);
        $node->addChild('FechaHoraModificado', $inmueble->FechaHoraModificado);
        $node->addChild('TipoInmueble', $inmueble->TipoInmueble);
        $node->addChild('TipoOperacion', $inmueble->TipoOperacion);
    }
}

echo $targetXML->asXML()


7 commentaires

Le premier code fonctionne très bien. Juste une question: l'un des éléments contient du code html
qui n'est pas copié (migré) vers le nouveau xml. Comment puis-je régler ça? Merci.


@JPashs pouvez-vous joindre un exemple de XML?


Voici l'url du vrai xlm: csainmobiliaria.com/imagenes/fotos/pisos.xml < / a> Et voici une capture où vous pouvez voir les balises html: postimg.cc/XrQDw9Xt Après avoir exécuté le code, l'onglet
html est supprimé du texte.


@Maxim_Fedorov avez-vous vu mon dernier commentaire.


@JPashs 3 DORMITORIOS, 1 CUARTO DE BAÑO

est un XML invalide. Par conséquent, SimpleXML tronque les balises HTML. Un élément doit contenir du HTML dans le bloc


Le XML dont vous parlez est parfaitement valide, bien qu'il utilise des balises HTML, il n'y a rien de mal avec l'imbrication des balises ou le format des balises.


@Maxim_Fedorov Alors, vous ne voyez aucun moyen d'intégrer les balises html dans le nouveau xml?



4
votes

DOMDocument vous permet de copier des structures de nœuds, donc plutôt que d'avoir pour copier tous les détails individuellement (qui peuvent être sujets à des données manquantes lorsque la spécification change), vous pouvez copier un nœud entier (tel que ) d'un document à un autre en utilisant importNode () qui a un paramètre pour indiquer que le contenu complet de l'élément doit être copié. Cette approche vous permet également de copier n'importe laquelle des tables en utilisant la même fonction sans changement de code ...

function extractData ( $sourceFile, $table, $newFileName )    {
    // Load source data
    $source = new DOMDocument();
    $source->load($sourceFile);
    $xp = new DOMXPath($source);

    // Create new file document
    $newFile = new DOMDocument();
    $newFile->formatOutput = true;
    // Create base element with the table name in new document
    $newRoot = $newFile->createElement($table);
    $newFile->appendChild($newRoot);

    // Find the records to copy
    $records = $xp->query('//Table[@Name="'.$table.'"]/*');
    foreach ( $records as $record ) {
        // Import the node to copy and append it to new document
        $importNode = $newFile->importNode($record, true);
        // Add new content
        $importNode->appendChild($newFile->createElement("Title", "value"));
        $newRoot->appendChild();
    }

    // Update Foto elements
    $xp = new DOMXPath($newFile);
    $fotos = $xp->query("//*[starts-with(local-name(), 'Foto')]");
    foreach ( $fotos as $foto ) {
        $path = $foto->nodeValue;
        if( substr($path, 0, 5) == "/www/" )    {
            $path = substr($path,4);
        }
        // Replace node with new version
        $foto->parentNode->replaceChild($newFile->createElement("Foto1", $path), 
                  $foto);
    }  

    $newFile->save($newFileName);
}
$xml_external_path = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos.xml';
$xml_external_savepath = 'saveFile.xml';

extractData ($xml_external_path, "Inmuebles", $xml_external_savepath);

Vous pouvez modifier la méthode pour renvoyer le document comme DOMDocument ou même une version SimpleXML si vous souhaitait le traiter davantage.

Pour SimpleXML, changez le retour en ...

$source = new DOMDocument();
$source->load($xml_external_path);

$newFile = new DOMDocument();
$newRoot = $newFile->createElement("Inmuebles");
$newFile->appendChild($newRoot);

// Find the records to copy
foreach ( $source->getElementsByTagName("Inmueble") as $record ) {
    $newRoot->appendChild($newFile->importNode($record, true));
}
echo $newFile->saveXML();

et vous pouvez l'appeler comme ... p>

$ret = extractData ($xml_external_path, "Inmuebles");
echo $ret->asXML();

Ou si vous voulez juste une façon fixe de faire cela, vous pouvez supprimer XPath et simplement utiliser getElementsByTagName () pour trouver les nœuds à copier. ..

return simplexml_import_dom($newRoot);

Pour ajouter le nom du fichier de sauvegarde, j'ai ajouté un nouveau paramètre à la fonction, cette nouvelle fonction ne renvoie rien du tout - elle charge juste le fichier et enregistre le résultat sous le nouveau nom de fichier ...

function extractData ( $sourceFile, $table )    {
    // Load source data
    $source = new DOMDocument();
    $source->load($sourceFile);
    $xp = new DOMXPath($source);

    // Create new data document
    $newFile = new DOMDocument();
    $newFile->formatOutput = true;
    // Create base element with the table name in new document
    $newRoot = $newFile->createElement($table);
    $newFile->appendChild($newRoot);

    // Find the records to copy
    $records = $xp->query('//Table[@Name="'.$table.'"]/*');
    foreach ( $records as $record ) {
        // Import the node to copy and append it to new document
        $newRoot->appendChild();
    }
    // Return the source of the XML
    return $newFile->saveXML();
}

echo extractData ($xml_external_path, "Inmuebles");


13 commentaires

@Nige_Ren J'essaye votre premier code. J'ai besoin de savoir comment enregistrer le nouveau xml sous un autre nom.


Si vous voulez enregistrer le XML dans un fichier, vous pouvez simplement enregistrer les données en utilisant file_put_contents ("outputFileName.xml", extractData ($ xml_external_path, "Inmuebles"));


@Nige_Ren merci, où exactement dois-je insérer cette ligne. Pouvez-vous envelopper la fonction complète?


J'ai ajouté une nouvelle version de la fonction dans laquelle vous pouvez transmettre le nom du fichier dans lequel enregistrer le résultat.


@Nige_Ren merci, votre dernier code function extractData ($ sourceFile, $ table, $ newFileName) ... fonctionne très bien.


@Nige_Ren J'exécute votre dernier code pour changer ce xml csainmobiliaria.com/imagenes/fotos /pisos-NOK.xml à ce csainmobiliaria.com/pisos-NEW- 2.xml . J'ai bien travaillé. Mais j'ai encore besoin de faire des remplacements de texte. Vous le verrez dans cette capture: postimg.cc/HcGXMGfW Comment puis-je faire cela? Pouvez-vous l'ajouter dans votre dernier code function extractData ($ sourceFile, $ table, $ newFileName) ... ? Merci.


$ table doit être échappé lorsqu'il est ajouté à XPath, pour la plupart pour la même raison, les variables dans les requêtes SQL doivent être échappées, voir stackoverflow.com/a/54436185/1067003


J'ai ajouté le segment de code commençant par // Mettre à jour les éléments Foto


Avez-vous déjà réglé cela?


Oui, je le fais fonctionner. Merci. Encore une question, y a-t-il un moyen d'ajouter un nouvel élément? Disons que j'ai besoin d'ajouter un élément personnalisé texte personnalisé à l'intérieur de chaque élément . Puis-je faire ceci?


J'ai mis à jour l'exemple (autour des lignes $ importNode = $ newFile-> importNode ) qui montrent comment vous pouvez modifier le nœud avant d'ajouter le contenu dans le nouveau document.


@NigelRen Merci. Pouvez-vous m'aider s'il vous plaît?: J'ai besoin d'imprimer un seul nœud qui se trouve à l'intérieur du nœud ... , celui-ci: 100002 < / IdPisoExterno> , je dois imprimer la valeur 100002 . Puis-je faire ceci?


Il vaut probablement mieux poser une nouvelle question car je suis absent depuis un certain temps et vous pourriez obtenir de l'aide d'autres personnes.



0
votes

Réfléchissez à nouveau, XSLT , le langage spécifique conçu pour les normes W3C pour modifier les fichiers XML selon les spécifications utilisateur requises, telles que vos besoins # 1-3. Comme l'autre langage déclaratif populaire, SQL, XSLT n'est pas limité à PHP mais portable vers d'autres couches d'application (Java, C #, Python, Perl, R) et dédié Processeurs XSLT 1.0, 2.0 et 3.0 .exe .

Avec cette approche, le style récursif de XSLT vous permet d'éviter toute boucle foreach , if logique, et des lignes répétées comme addChild ou appendChild appelle au niveau de la couche application.

XSLT (enregistrer en tant que fichier .xsl, fichier .xml spécial ou chaîne intégrée; portable vers d'autres interfaces au-delà de PHP)

<?xml version="1.0" encoding="ISO-8859-1"?>
<Inmuebles>
   <Inmuebles>
      <IdInmobiliariaExterna>B45695855</IdInmobiliariaExterna>
      <IdPisoExterno>100002</IdPisoExterno>
      <FechaHoraModificado>30/11/2018</FechaHoraModificado>
      <TipoInmueble>PISO</TipoInmueble>
      <TipoOperacion>3</TipoOperacion>
   </Inmuebles>
   <Inmuebles>
      <IdInmobiliariaExterna>B45695855</IdInmobiliariaExterna>
      <IdPisoExterno>100003</IdPisoExterno>
      <FechaHoraModificado>30/11/2018</FechaHoraModificado>
      <TipoInmueble>CHALET</TipoInmueble>
      <TipoOperacion>4</TipoOperacion>
   </Inmuebles>
</Inmuebles>

Démo XSLT

PHP (en utilisant la bibliothèque php_xsl )

// LOAD XML SOURCE
$url = 'http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml';
$web_data = file_get_contents($url);
$xml = new SimpleXMLElement($web_data);

// LOAD XSL SCRIPT
$xsl = simplexml_load_file('/path/to/script.xsl');

// XSLT TRANSFORMATION
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); 
$newXML = $proc->transformToXML($xml);

// OUTPUT TO CONSOLE
echo $newXML;

// SAVE TO FILE
file_put_contents('Output.xml', $newXML);

Et en tant que grand gourou XSLT, @Dimitre Novatchev , termine généralement ses messages: le résultat recherché et correct est produit :

<?xml version="1.0"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" indent="yes" encoding="ISO-8859-1"/>
     <xsl:strip-space elements="*"/>

     <!-- WALK DOWN TREE FROM ROOT -->
     <xsl:template match="Publication">
        <xsl:apply-templates select="Table"/>
     </xsl:template>

     <xsl:template match="Table[@Name='Inmuebles']">
         <Inmuebles>
             <xsl:apply-templates select="*"/>
         </Inmuebles>
     </xsl:template>

     <!-- EMPTY TEMPLATE TO REMOVE SPECIFIED NODES -->
     <xsl:template match="Table[@Name='Agencias']"/>

     <!-- RETURN ONLY FIRST FIVE NODES -->
     <xsl:template match="Table/*">
         <Inmuebles>
             <xsl:copy-of select="*[position() &lt;= 5]"/>
         </Inmuebles>
     </xsl:template>

</xsl:stylesheet>


0 commentaires