【问题标题】:PHP & XML Creation: Node in wrong parentPHP & XML 创建:错误的父节点
【发布时间】:2016-08-09 01:32:02
【问题描述】:

我目前正在开发一个 MVC 风格的基于 OOP 的 PHP 项目。 对于我的项目,我需要创建/发送/接收/处理 XML。

现在我在用 DOMDocument 创建 XML 结构时遇到了一个大问题。 每次我创建一个没有 attributesvalues 的新 XML 节点时,如果此节点之后的所有节点都将是子节点!

换句话说:我不能创建一个空 XML 节点,之后所有节点都不是 这个空节点的子节点!! !

这个问题困扰了我一段时间,但我真的需要我现在处理 XML 创建的方式。 除了一些类似的问题,我找不到任何解决方案。

这个 PHP 测试了我的 XmlHandler-Class,它创建了 XML-Request:

Test.php:

<?php

include "Handler/XmlHandler.php";


$xmlHandler=new XmlHandler();

$xmlHandler->CreateNewXmlInstance();
$root = $xmlHandler->CreateRootNode('RootNode');
$l1 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel1", "Text1 - This node one has text");
$l2 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel2", "Text2 - Next node Level3 level is not gonna have text");
$l21 = $xmlHandler->AppendNodeWithChild($l2, "NodeLevel2_1", "Text2_1 - This node will be a child of Level2, everything fine");
$l3 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel3", "");
$l4 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel4", "Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)");

echo "<p style='display:none;'>".$xmlHandler->SaveXml()."</p>";

?>

这是我用来创建 XML-Request-Structure 的 XML-Handler 类(我只是在这里发布了该类的必要部分)

XmlHandler.php:

<?php 

class XmlHandler{


    private $xml;

    /**
     *
     *    Constructor
     *
     */

    function __construct()
    {
        $this->xml=null;

    }

    //[...]

    /*
    *   Custom XML-Creator Functions 
    *
    */

    public function CreateNewXmlInstance(){
        /*********************************************/
        /** XML DOM example of building XML Request **/
        /*********************************************/
        $this->xml = new DOMDocument('1.0', 'UTF-8');
        return $this->xml;
    }

    public function CreateRootNode($name){
        $rootElement = $this->xml->appendChild( $this->xml->createElement($name) );
        return $rootElement;
    }

    public function AppendNodeWithChild($node, $childName, $childText){
        $result = $node->appendChild($this->xml->createElement($childName));
        if(null != $childText && !empty($childText)){
            $result->appendChild( $this->xml->createTextNode($childText) );
        }

        return $result;
    }

    public function SetNodeAttributes($node, $nameAndValues){
        if(null != $nameAndValues && sizeof($nameAndValues) > 0){
            foreach($nameAndValues as $name => $value){
                $this->SetNodeAttribute($node, $name, $value);
            }
        }
    }

    public function SetNodeAttribute($node, $name, $value){
        $node->setAttribute($name, $value);
    }

    public function SaveXml(){
        return $this->xml->saveXML();
    }

    //[...]

}

?>

这是结果:

<!-- ?xml version="1.0" encoding="UTF-8"? -->
<rootnode>
    <nodelevel1>Text1 - This node one has text</nodelevel1>
    <nodelevel2>Text2 - Next node Level3 level is not gonna have text
        <nodelevel2_1>Text2_1 - This node will be a child of Level2, everything fine</nodelevel2_1>
    </nodelevel2>
    <nodelevel3>
        <nodelevel4>Text4 - This node should be on same level like 3, 2 &amp; 1, but instead it's a child of Level 3 (?!?!?!?!)</nodelevel4>
    </nodelevel3>
</rootnode>

但理论上应该是这样的:

<!-- ?xml version="1.0" encoding="UTF-8"? -->
<rootnode>
    <nodelevel1>Text1 - This node one has text</nodelevel1>
    <nodelevel2>Text2 - Next node Level3 level is not gonna have text
        <nodelevel2_1>Text2_1 - This node will be a child of Level2, everything fine</nodelevel2_1>
    </nodelevel2>
    <nodelevel3/>
    <nodelevel4>Text4 - This node should be on same level like 3, 2 &amp; 1, but instead it's a child of Level 3 (?!?!?!?!)</nodelevel4>
</rootnode>

如您所见:当我没有为 Level3 上新创建的节点设置值时出现问题!:

$l3 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel3", "");
$l4 = $xmlHandler->AppendNodeWithChild($root, "NodeLevel4", "Text4 - This node should be on same level like 3, 2 & 1, but instead it's a child of Level 3 (?!?!?!?!)");

只要我设置属性或在新创建的节点中输入值,一切都很好。 但是我在某些情况下也必须创建纯空节点!

我的问题是:

我在这里做错了什么?

还是 PHP 做错了什么?

也许我的浏览器对 XML 的准备工作很糟糕,但是传出的 XML 请求是正确构建和发送的,而错误在于其他原因?

如果是这样,我该如何检查 XML 请求?

编辑 Nr.2:

我以某种方式更改了我的问题/原始帖子。 上面的例子更容易理解。 至少我希望如此。

【问题讨论】:

    标签: php xml oop soap domdocument


    【解决方案1】:

    将您的辅助函数包装在一个类中

    class XMLHelper {
        /*
        *   Custom XML-Creator Functions
        *
        */
    
        private $xml;
    
        public function CreateNewXmlInstance(){
            /*********************************************/
            /** XML DOM example of building XML Request **/
            /*********************************************/
            $this->xml = new DOMDocument('1.0', 'UTF-8');
            return $this->xml;
        }
    
        public function CreateRootNode($name){
            $rootElement = $this->xml->appendChild( $this->xml->createElement($name) );
            return $rootElement;
        }
    
        public function AppendNodeWithChild($node, $childName, $childText){
            $result = $node->appendChild($this->xml->createElement($childName));
            if(null != $childText && !empty($childText)){
                $result->appendChild( $this->xml->createTextNode($childText) );
            }
    
            return $result;
        }
    
        public function SetNodeAttributes($node, $nameAndValues){
            if(null != $nameAndValues && sizeof($nameAndValues) > 0){
                foreach($nameAndValues as $name => $value){
                    $this->SetNodeAttribute($node, $name, $value);
                }
            }
        }
    
        public function SetNodeAttribute($node, $name, $value){
            $node->setAttribute($name, $value);
        }
    
        public function SaveXml(){
            return $this->xml->saveXML();
        }
    }
    

    在类中包装内容,因为您的代码包含$this 调用

    在类中包装事物使$this 调用以更正程序所需的变量。

    然后新建类并初始化节点

    $test = new XMLHelper();
    $test->CreateNewXmlInstance();
    $request = $test->CreateRootNode("request");
    $node1 = $test->AppendNodeWithChild($request, "node1", null);
    $node2 = $test->AppendNodeWithChild($node1, "node2", null);
    $test->SetNodeAttributes($node2, array(
        "client" => "This is a testing value"
    ));
    
    echo $test->saveXml();
    
    //Output: 
    //    <?xml version="1.0" encoding="UTF-8"?>
    //    <request>
    //        <node1>
    //            <node2 client="This is a testing value"/>
    //        </node1>
    //    </request>
    

    请注意,代码需要按正确的顺序执行。

    1. 新建根节点(请求)
    2. 然后将节点1附加到(请求)
    3. 最后将节点 2 附加到节点 1
    4. 配置节点2的客户端值
    5. 打印出整个根节点
    6. 那么你就完成了魔法

    PHP 没有任何问题,您的 Web 浏览器也没有问题。

    这个错误可能是因为你没有初始化根节点,没有将创建的节点正确添加到根节点

    有关 php 中的 XML 验证,请参阅this link

    DOMDocument 有一个内置的验证函数。

    编辑 2016-08-10

    这里是你的案例修改后的代码

    class SpecificXmlHandler extends XmlHandler{
    
        /**
         *    Constructor
         *
         */
    
        private $errorCounter;
        private $xmlUrl;
    
        //Declare the root first
        private $root;
    
        function __construct()
        {
            parent::__construct();
            $this->errorCounter=0;
            $this->xmlUrl=Configuration::XML_REQUEST_URL;
        }
    
    
        //[...]
    
        /**
         *   Action Functions
         */
    
        public function GetStaticData($requestName, $requestFilterNamesAndValues){
            $xml = $this->BuildStaticDataRequest($requestName, $requestFilterNamesAndValues);
            echo "<p style='display:none'>" . $xml. "</p>";     //Request
            $response = $this->ExecuteRequest($this->xmlUrl, $xml, null, false);
            echo "<p style='display:none'>" . $response . "</p>"; //Resonse
    
            //[...]
        }
    
        //[...]
    
        /**
        *   Request Building Functions
        */
    
        public function BuildStaticDataRequest($requestName, $requestFilterNamesAndValues){
    
            $this->CreateNewXmlInstance();
            //$root = $this->CreateRootNode('Request');
            //Use the root node you have created in the constructor by using $this
            $this->root = $this->CreateRootNode('Request');
            //Generate Header (Source-Node)
            $this->GenerateHeadData($this->root);
    
            //[...]
    
            return $this->SaveXml();
        }
    
        public function GenerateHeadData($root){
    
            $clientID=Configuration::XML_CLIENT;
    
    
            //Here the Node1 & Node2 creation
            $node1 = $this->AppendNodeWithChild($root, "node1", null);
            $node2 = $this->AppendNodeWithChild($node1, "node2", null);
    
            $this->SetNodeAttributes( $node2 , array(
                "Client" =>$clientID
            ));
    
            //Change it to return the whole root
            return $root;
    
        }
    
    [...]
    
    
    }
    

    请在类中创建变量,并使用$this 引用您创建的私有变量。

    【讨论】:

    • 您好 MiKeNeko,感谢您的回复。我的代码已经像您在答案中描述的那样。就像我说的,我正在开发OOP。但我仍然遇到 node2 不在 node1 中的问题。
    • 我在原来的帖子中添加了更多的类代码。我不知道错误在哪里。你的步骤是:New the root node ( request ) //CHECK Then append a node 1 to ( request ) //CHECK Finally append node 2 to node 1 //CHECK Configure the client value of node 2 //CHECK Print out the whole root node //CHECK Then you've done the magic //CHECK 或者我错过了什么?
    • 我已经对答案进行了更新,看看是否有帮助。我想你错过了$this。请查看我的更新代码。
    • 你好。感谢您的帮助,但没有理由将 local $root 变量更改为 global 变量。我找到了我猜的原因,但我不知道为什么会这样。请参阅我上面编辑的帖子了解更多信息。正如您将看到的,主要原因是创建的节点没有任何 valuesattributes(空节点)!
    【解决方案2】:

    好的,有人帮我解决了这个问题。 以下是对话:

    他:标签错了(因为它们已经改成全小写了)

    我:是的,似乎 XML 在 回显 进入浏览器而不是保存 进入文件

    他:而且输出甚至不应该被格式化

    我:我自己这样做是为了看得更清楚

    他:这是启用格式化输出后$xmlHandler->SaveXml()的原始输出

    <?xml version="1.0" encoding="UTF-8"?>
    <RootNode>
      <NodeLevel1>Text1 - This node one has text</NodeLevel1>
      <NodeLevel2>Text2 - Next node Level3 level is not gonna have text<NodeLevel2_1>Text2_1 - This node will be a child of Level2, everything fine</NodeLevel2_1></NodeLevel2>
      <NodeLevel3/>
      <NodeLevel4>Text4 - This node should be on same level like 3, 2 &amp; 1, but instead it's a child of Level 3 (?!?!?!?!)</NodeLevel4>
    </RootNode>
    

    我:打印文件后,我得到了和你一样的结果。

    结论:

    现在我已将 saveXml 输出写入文件。 结果是他和告诉我的一样。

    那么乱吗?

    我认为使用 echo 将 XML 打印到浏览器中并通过 FireFox 通过 HTML 源代码检查就足够了。

    正如你在我的第一篇文章中看到的,我使用了 echo...

    echo "<p style='display:none;'>".$xmlHandler->SaveXml()."</p>";
    

    以某种方式打印出我的 XML-Creation 的结果(因为我不知道该怎么做)。

    因此,XML-Creation 从启动开始就完全成功,而我从响应服务器得到的错误位于其他地方(从现在开始,我不能再依赖你的帮助了)!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多