asXML()不保存更改

时间:2014-08-22 15:16:15

标签: php xml simplexml

我有一个带嵌套命名空间的复杂xml,我正在尝试执行以下操作:

1)打开XML文件 2)验证XSD架构 3)解析它 4)更改节点(当时为1,将它们设置为null或其他变量) 5)将更改的xml保存到新文件中 5)Ri-验证它与2)相同的模式,并确保弹出错误。

现在,1-2-3和5-6点不是问题。将更改+保存到新的xml中是。

XML代码段:

 <Movie creationDateTime="2014-05-14T13:42:52Z" endDateTime="2015-05-14T00:00:00Z"       providerVersionNum="5" startDateTime="2014-05-14T00:00:00Z" uriId="disney.chlsd.com/MOOT0000000000020902">
<core:Ext>
  <ext:MovieExtensions analogueOff="true" mediaId="CGOT0000000000020902">
    <ext:assetPart partNum="1">
      <ext:SourceUrl>DSNY0000000000020902.mxf</ext:SourceUrl>
      <ext:ContentFileSize>46166173874</ext:ContentFileSize>
      <ext:ContentCheckSum>4da3e4cafd4f3262d136c519311a7b53</ext:ContentCheckSum>
      <ext:SOE>PT09H59M30S00F</ext:SOE>
      <ext:SOM>PT10H00M00S00F</ext:SOM>
      <ext:EOM>PT10H46M02S11F</ext:EOM>
    </ext:assetPart>
    <ext:playlistSupportOnly>false</ext:playlistSupportOnly>
  </ext:MovieExtensions>
    </core:Ext>
    <content:AudioType>Stereo</content:AudioType>
    <content:FrameRate>25</content:FrameRate>
    <content:Codec>H.264</content:Codec>
    <content:AVContainer>MXF</content:AVContainer>
    <content:Duration>PT00H46M02S</content:Duration>
    <content:IsHDContent>false</content:IsHDContent>
</Movie>

我使用($ mypix是我加载Xml的XmlSimpleObject)对属性进行解析:

$xmlfile = "prova.xml";
$mypix = simplexml_load_file($xmlfile);

[...]

           foreach ($mypix->children() as $parent => $child)
        { 
             echo "<br/>Main Node: ".(String)$parent."<br/>";

             foreach ($mypix->children()->attributes() as $a => $b) 
                 {
                    echo "Main attribute: ".(String)$a. "     with value: ".(String)$b."<br/>";                     
                        if ($a == "endDateTime")
                          { 
                            echo "Entering node: ".$a." and eliminating: ".$b." <br/>";
                            $b=NULL;                            
                            echo "<br/><pre>";
                            echo $mypix->asXML("t.xml");
                            echo "<br/></pre>";
                          }

                } 
        }   

解析给了我:

Main Node: Movie
Main attribute: creationDateTime with value: 2014-05-16T14:40:41Z
Main attribute: endDateTime with value: 2015-05-16T00:00:00Z
  
    
      

输入节点:endDateTime并消除:2015-05-16T00:00:00Z

    
  

问题是,当我打开t.xml时,endDateTime仍然是一个有效的标签(绝对不是空的)。

=============================================== ==========================

我尝试过的事情:

使用Xpath的替代方法:

$namespaces = $mypix->getNameSpaces(true);
        $mypix->registerXPathNamespace('ext', 'URN:NNDS:CMS:ADI3:01');
        $mypix->registerXPathNamespace('title', 'http://www.cablelabs.com/namespaces/metadata/xsd/title/1');
        $mypix->registerXPathNamespace('core', 'http://www.cablelabs.com/namespaces/metadata/xsd/core/1');

        echo "<br/><br/>";
        // Getting Episode Name
        $xtring = ($mypix->xpath('//core:Ext/ext:LocalizableTitleExt/ext:EpisodeName'));          
        echo "<br/><b>EpisodeName: </b>".$xtring[0]."<br/>";
        $xtring[0] = NULL; 
        echo $mypix->asXML("t.xml"); // Nothing again

这里xpath查询返回一个有效值,但更改&amp;写入新文件失败

第二次尝试:保存到同一个文件('prova.xml')而不是't.xml'(如果我搞砸了SimpleXMlObjects)......没什么......

请帮忙吗?

1 个答案:

答案 0 :(得分:0)

将变量设置为null不会删除,销毁或编辑变量用于指向的对象。

你可能已经看过这样一个例子,这是一种有效的方式来清理&#34;类似于数据库连接对象的东西,因为当您删除对象的所有引用时,its destructor will be called。但是,这不是这种情况,因为$b指向的对象仍然可以访问,例如从另一个电话$mypix->children()->attributes()

另一件事you will have seen in examples是使用$element->someChild = 'new value';$element['someAttribute'] = 'new value';等语法为子元素或属性分配新值。但是,这是有效的,因为SimpleXML重载属性访问(->)和数组元素访问([...]),与实现__set()ArrayAccess::offsetSet()以及您的代码相同不使用那些。

一种使用数组访问重载的方法来删除或删除你有一个直接指向变量的元素,这就是偏移量[0]指向当前元素。因此,您可以编写unset($b[0]);来完全删除元素或属性;你也可以写$b[0] = '';来清空一个元素,但是这里有一个属性,这会导致一个致命的错误(我怀疑是一个错误)。

请注意,当您使用XPath时,实际上并未实现此自引用或重载运算符,因为SimpleXMLElement::xpath返回一个普通数组,因此$xtring[0]只是一个普通的PHP变量。由于它是该示例中的元素,因此您可以使用自引用将其删除,方法是编写unset($xtring[0][0]);或将其与$xtring[0][0] = '';

一起删除

然而,尽管如此,您的代码实际上可以大规模简化,以避免任何必要的代码。让我们逐行分开:

 foreach ($mypix->children() as $parent => $child)

此处的变量$mypix用于比您在样本中显示的文档更大的文档,该示例显然只是此循环中的一个条目。请注意,此处的$parent => $child更适合命名为$childName => $child

您很可能只对具有特定名称的孩子感兴趣,因此最常见的循环形式是foreach ($mypix->Movie as $child)

foreach ($mypix->children()->attributes() as $a => $b)

在这里,您完全忽略外部循环的进度,然后返回整个文档。 SimpleXML会将$mypix->children()->...解释为$mypix->children()[0]->...,它只会查看第一个孩子。你真的想要foreach ($child->attributes() ...

if ($a == "endDateTime")

由于您正在寻找具有特定名称的属性,因此您实际上根本不需要遍历attributes(),您可以直接以$child['endDateTime']方式访问它。请注意,由于我们现在使用重载的[...]运算符,我们可以使用它来回写或删除属性。

echo $mypix->asXML("t.xml");

SimpleXMLElement::asXML或者将文档作为字符串保存到文件中,而不是两者都保存。因为在后一种情况下,它返回一个布尔值echo,结果不太可能非常有用。

每次围绕内循环,您也在调用此函数,从而多次保存同一文件。当您完成所有修改后,您只需要执行一次。


所以,这是我写代码的方式

foreach ( $mypix->Movie as $child )
{
     $child['endDateTime'] = null; 
     // or to remove the attribute completely: unset($child['endDateTime']);
}
$mypix->asXML('t.xml');

或者,对于第二个例子,但是没有XPath(啰嗦,但如果你一次改变几件事情就很有用,那么就不要想&#34;跳到&#34;到最深的后代文献)。请注意使用->children($ns_uri)切换到不同的命名空间。

// Constants for handier but implementation-independent reference to namespaces
define('XMLNS_EXT', 'URN:NNDS:CMS:ADI3:01');
define('XMLNS_TITLE', 'http://www.cablelabs.com/namespaces/metadata/xsd/title/1');
define('XMLNS_CORE', 'http://www.cablelabs.com/namespaces/metadata/xsd/core/1');

foreach ( $mypix->children() as $child )
{
    foreach ( $child->children(XMLNS_CORE)->Ext as $ext )
    {
         foreach ( $ext->children(XMLNS_EXT)->LocalizableTitleExt as $title )
         {
             // Delete a child node; note not ->children() as "ext" namespace already selected
             unset($title->EpisodeName);
         }
    }
}
$mypix->asXML("t.xml");