【问题标题】:asXML() not saving changesasXML() 不保存更改
【发布时间】:2014-10-16 12:08:05
【问题描述】:

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

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

现在,第 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 查询返回一个有效值,但更改和写入新文件失败

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

有什么帮助吗?

【问题讨论】:

    标签: php xml simplexml


    【解决方案1】:

    将变量设置为null 不会删除、销毁或编辑该变量曾经指向的对象。

    您可能已经看到了这样的示例,这些示例是“清理”诸如数据库连接对象之类的有效方法,因为当您删除对象的 所有 引用时,its destructor will be called。但是,这里不是这样,因为$b 指向的对象仍然可以访问,例如从另一个电话到$mypix-&gt;children()-&gt;attributes()

    另一件事you will have seen in examples 是使用$element-&gt;someChild = 'new value';$element['someAttribute'] = 'new value'; 等语法为子元素或属性分配新值。但是,这是可行的,因为 SimpleXML 重载了属性访问 (-&gt;) 和数组元素访问 ([...]),与实现 __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 =&gt; $child 更适合命名为$childName =&gt; $child

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

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

    在这里,您完全忽略了外循环周围的进度,并返回到整个文档。 SimpleXML 会将$mypix-&gt;children()-&gt;... 解释为$mypix-&gt;children()[0]-&gt;...,即只查看第一个孩子。你实际上想要foreach ($child-&gt;attributes() ...

    if ($a == "endDateTime")
    

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

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

    SimpleXMLElement::asXML 要么将文档作为字符串返回,要么 保存到文件,而不是两者。由于在后一种情况下它返回一个布尔值,echoing 该结果不太可能很有用。

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


    所以,我会这样写代码

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

    或者,对于第二个示例,但没有 XPath(冗长,但如果您同时更改几项内容很有用,因此不要“跳转”到文档中最深的后代)。注意使用-&gt;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");
    

    【讨论】:

    • 朋友,谢谢。只是谢谢。您花时间深入研究我的代码并提供了如此广泛而周到的答复,我感到敬畏并且非常感谢。再次感谢,现在将尝试实施!
    猜你喜欢
    • 1970-01-01
    • 2017-10-26
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-14
    • 2021-02-09
    相关资源
    最近更新 更多