Получить XML-файл, чтобы найти и заменить текст. PHP - PullRequest
0 голосов
/ 25 января 2019

Мне нужно изменить текст в файле XML, используя код PHP. Затем я создал код для:

1 - получить файл

2 - заменить текст

3 - сохранить файл под другим именем.

Проблема в том, что у меня возникли проблемы с заменой текста в XML-файле.

Я могу заменить простые строки, но не могу заменить текст такими символами, как '<'. Ниже реальный код и файлы. </p>

Исходный XML-путь: http://www.csainmobiliaria.com/imagenes/fotos/pisos-NOK.xml

1) Этот код просто меняет текст Inmuebles на xxxxxxxx. Это прекрасно работает

    $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');

2) Теперь, если я использую этот код для изменения текста <Table Name="Inmuebles"> на <xxxxxxxx> , я получаю ОШИБКУ 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) Таким же образом, если я использую этот код для удаления текста Publicacion , я получаю ОШИБКУ 500.

    $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');

Это конечный результат, который мне нужно получить: http://www.csainmobiliaria.com/imagenes/fotos/pisos-OK.xml

Захват: enter image description here

Ответы [ 3 ]

0 голосов
/ 28 января 2019

DOMDocument позволяет вам копировать структуры узлов, поэтому вместо того, чтобы копировать все детали по отдельности (что может привести к отсутствию данных при изменении спецификации), вы можете скопировать весь узел (например,как <Inmueble>) из одного документа в другой, используя importNode(), у которого есть параметр, указывающий, что необходимо скопировать все содержимое элемента.Этот подход также позволяет вам копировать любую из таблиц, используя одну и ту же функцию, без изменения кода ...

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");

Вы можете изменить метод так, чтобы он возвращал документ как DOMDocument или даже версию SimpleXML, если вы хотитеобработайте его далее.

Для SimpleXML измените возвращаемое значение на ...

return simplexml_import_dom($newRoot);

, а затем вы можете назвать его как ...

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

Или есливам просто нужен фиксированный способ сделать это, вы можете удалить XPath и просто использовать getElementsByTagName(), чтобы найти узлы для копирования ...

$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();

Чтобы добавить имя файла сохранения, я добавилновый параметр функции, эта новая функция вообще ничего не возвращает - она ​​просто загружает файл и сохраняет результат в новом имени файла ...

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);
0 голосов
/ 03 февраля 2019

Рассмотрим еще раз, XSLT , специальный язык, совместимый со стандартами W3C, предназначенный для изменения XML-файлов в соответствии с необходимыми пользовательскими спецификациями, такими как # 1-3.Как и другой популярный декларативный язык, SQL, XSLT не ограничен PHP, но переносим на другие уровни приложений (Java, C #, Python, Perl, R) и выделен XSLT 1.0, 2.0 и 3.0.exe процессоры .

При таком подходе рекурсивное моделирование XSLT позволяет избежать циклов foreach, логики if и повторяющихся строк, таких как addChild или appendChild, в приложении.layer.

XSLT (сохранить в виде файла .xsl, специального файла .xml или встроенной строки; можно переносить на другие интерфейсы помимо PHP)

<?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>

XSLT Demo

PHP (с использованием библиотеки 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);

Икак великий гуру XSLT, @ Dimitre Novatchev обычно заканчивает свои посты: желаемый, правильный результат получается :

<?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>
0 голосов
/ 28 января 2019

Вы можете скопировать нужный узел вместо удаления лишних элементов. Например, вы можете скопировать Inmuebles узел с помощью SimpleXML:

$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()

Также, как сказал @ThW в комментариях, вы можете использовать XLST , например:

$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();
...