使用 PHP 替换 xml/plist 文件中的字符串

Posted

技术标签:

【中文标题】使用 PHP 替换 xml/plist 文件中的字符串【英文标题】:Replacing a string in an xml/plist file using PHP 【发布时间】:2019-12-27 19:24:36 【问题描述】:

我在一个目录中有两个.plist 文件,它们看起来都像这样:

<dict>
    <key>bundle-identifier</key>
    <string>TEXT</string>
    <key>bundle-version</key>
    <string>VESRION</string>
    <key>kind</key>
    <string>software</string>
    <key>subtitle</key>
    <string>TEXT</string>
    <key>title</key>
    <string>TEXT</string>
  </dict>

我能够通过以下方式获得 title 的值/字符串:

$files = array();
foreach (glob("../../plists/*.plist") as $file) 
    $files[] = $file;
    //echo "$file";

    $fileContent = file_get_contents($file);
    $xml = simplexml_load_string($fileContent) or die("Error: Cannot create object");
    $resultNames = $xml->dict->array->dict->dict->string[4] . '<br /> <br />';
    //echo $resultNames;


现在我想用 php 为它们中的每一个更改 title 的值/字符串,就像我更改其中一个的 title 值/字符串一样不想让对方受其影响,有可能吗?

【问题讨论】:

【参考方案1】:

不确定标题的回显是如何工作的,但在这段代码中,我使用 XPath 来查找具有内容 title&lt;key&gt; 元素。然后它获取以下&lt;string&gt; 元素的值。

要更新它,您可以在 SimpleXML 中稍加修改,使其设置 &lt;string&gt; 元素的值,然后将结果 XML 保存回相同的文件名......

$xml = simplexml_load_string($fileContent) or die("Error: Cannot create object");
// Find the correct string element from the preceding key for title
$titleString = $xml->xpath('//key[.="title"]/following-sibling::string')[0];

// Set new value
$titleString[0] = "new Title1";
// Save the file
$xml->asXML($file);

如果您通过文件名识别内容,则检查$file,但如果您只能通过标题识别它,那么您需要检查这是否找到了您想要的标题。

$titleToUpdate = "Correct Title2";
$fileContent = file_get_contents($file);
$xml = simplexml_load_string($fileContent) or die("Error: Cannot create object");
$titleString = $xml->xpath('//key[.="title"]/following-sibling::string[.="'.$titleToUpdate.'"]');


// Check there is 1 matching item
if ( count($titleString) == 1 )  
    $titleString[0][0] = "new Title12";
    $xml->asXML($file);

【讨论】:

好的,这行得通,但它改变了两个 .plist 文件的标题,我认为那是因为我使用 *.plist,我该怎么办? 这是我的问题的一部分。 我将其中一个标题更改为 test 并将 $titleToUpdate = "Correct Title2"; 更改为 $titleToUpdate = "test "; 但它并没有改变文件中的标题,我错过了什么吗?顺便说一句,如果我的 Q 不够清楚,对不起:( titleTEXTTEXT 更改为 test 【参考方案2】:

我不确定是否了解所有内容,但您可以使用 DomDocument 更改值。

$doc = new DOMDocument;
$doc->load('your_xml_file.xml');

$elements = $doc->getElementsByTagName("string");

foreach ($elements as $element) 
   //$element->nodeName will be "string"
   $nodes = $element->childNodes;

   foreach ($nodes as $node) 
      $node->nodeValue = 'New value';
    


$doc->save("newfile.xml")

【讨论】:

这可能有效,但如果不知道确切的文件名怎么办?我可以使用 glob 吗? 您可以像这样使用字符串变量:doc-&gt;loadXML($string_variable_that_content_your_xml); 如果您的变量不包含有效的 XML,它将返回 false,因此您应该检查返回值。【参考方案3】:

它不漂亮,但很有效。

$doc = new DOMDocument;
$doc->load('file_address');

$elements = $doc->documentElement;

$found = false;
foreach ($elements->childNodes AS $item) 
    if($found)
        $item->nodeValue = 'changed';
        $found = false;
    else
        if($item->nodeName == 'key' && $item->nodeValue == 'title')
            $found = true;
        
    

$doc->saveXML();

【讨论】:

【参考方案4】:

在 DOM 中使用 Xpath 也是可能的。

$titleToUpdate = 'Original Title';

$document = new DOMDocument();
// load from string, for file: $document->load($fileName);
$document->loadXML($xml);
$xpath = new DOMXpath($document);

$expression = '//dict/key[.="title"]/following-sibling::string[.="'.$titleToUpdate.'"]';

$modified = FALSE; 
foreach ($xpath->evaluate($expression) as $titleValueNode) 
    $titleValueNode->textContent = 'Changed Title';
    $modified = TRUE;


if ($modified) 
  // output string, to save file: $document->save($fileName);
  echo $document->saveXML();

输出:

<?xml version="1.0"?>
<dict>
    <key>bundle-identifier</key>
    <string>TEXT</string>
    <key>bundle-version</key>
    <string>VESRION</string>
    <key>kind</key>
    <string>software</string>
    <key>subtitle</key>
    <string>TEXT</string>
    <key>title</key>
    <string>Changed Title</string>
</dict>

这种方法会更改任何匹配的项目,并只存储它修改过的一个或多个。

现在,如果您确实需要为此查找不同的文件,我建议您将操作移至函数中。

function replaceTitle(string $fileName, string $title): bool 
    // the actual action from the example
    return $modified;


$files = new GlobIterator(__DIR__.'/path/*.plist');
foreach ($files as $file) 
    if (replaceTitle((string)$file, 'Original Title')) 
        echo "Modified: $file\n";
    

【讨论】:

以上是关于使用 PHP 替换 xml/plist 文件中的字符串的主要内容,如果未能解决你的问题,请参考以下文章

Racket 中的 Plist/XML 解析

php替换大括号内的文字

记忆sed的命令

使用 PHP 替换文本文件中的字符串

写一个C程序完成字串替换操作,将串s中的字串t全部换成串v

如何使用 PHP 替换 PDF 文件中的内容?