【问题标题】:PHP SimpleXML recursive function to list children and attributesPHP SimpleXML 递归函数列出子项和属性
【发布时间】:2011-01-23 18:10:58
【问题描述】:

对于列出元素名称和属性的递归函数的 SimpleXML 调用,我需要一些帮助。创建一个 XML 配置文件系统,但每个脚本都有自己的配置文件以及新的命名约定。所以我需要一种简单的方法来映射所有具有属性的元素,所以就像在示例 1 中一样,我需要一种简单的方法来调用所有进程,但我不知道如何在不对元素名称进行硬编码的情况下执行此操作函数调用。有没有办法递归调用函数来匹配子元素名称?我确实看到了 xpath 功能,但我没有看到如何将其用于属性。

示例中的 XML 看起来是否正确?我可以这样构造我的 XML 吗?

示例 1:

<application>
  <processes>
    <process id="123" name="run batch A" />
    <process id="122" name="run batch B" />
    <process id="129" name="run batch C" />
  </processes>
  <connections>
    <databases>
      <database usr="test" pss="test" hst="test" dbn="test" />
    </databases>
    <shells>
      <ssh usr="test" pss="test" hst="test-2" />
      <ssh usr="test" pss="test" hst="test-1" />
    </shells>
  </connections>
</application>

示例 2:

<config>
  <queues>
    <queue id="1" name="test" />
    <queue id="2" name="production" />
    <queue id="3" name="error" />
  </queues>
</config>

伪代码:

// Would return matching process id
getProcess($process_id) {
  return the process attributes as array that are in the XML
}

// Would return matching DBN (database name)
getDatabase($database_name) {
  return the database attributes as array that are in the XML
}

// Would return matching SSH Host
getSSHHost($ssh_host) {
  return the ssh attributes as array that are in the XML
}

// Would return matching SSH User
getSSHUser($ssh_user) {
  return the ssh attributes as array that are in the XML
}

// Would return matching Queue 
getQueue($queue_id) {
  return the queue attributes as array that are in the XML
}

编辑:

我可以通过两个参数吗?关于你建议的第一种方法@Gordon

我刚收到,thnx,见下文

public function findProcessById($id, $name)
{
    $attr = false;
    $el = $this->xml->xpath("//process[@id='$id'][@name='$name']"); // How do I also filter by the name?
    if($el && count($el) === 1) {
        $attr = (array) $el[0]->attributes();
        $attr = $attr['@attributes'];
    }
    return $attr;
}

【问题讨论】:

    标签: php xml configuration recursion simplexml


    【解决方案1】:

    XML 对我来说看起来不错。我唯一不会做的就是让 name 成为 process 中的一个属性,因为它包含空格并且应该是一个文本节点(在我看来)。但既然 SimpleXml 没有抱怨,我想这归结为个人喜好。

    我可能会使用 DataFinder 类来解决这个问题,封装 XPath 查询,例如

    class XmlFinder
    {
        protected $xml;
        public function __construct($xml)
        {
            $this->xml = new SimpleXMLElement($xml);
        }
        public function findProcessById($id)
        {
            $attr = false;
            $el = $this->xml->xpath("//process[@id='$id']");
            if($el && count($el) === 1) {
                $attr = (array) $el[0]->attributes();
                $attr = $attr['@attributes'];
            }
            return $attr;
        }
        // ... other methods ...
    }
    

    然后使用它

    $finder = new XmlFinder($xml);
    print_r( $finder->findProcessById(122) );
    

    输出:

    Array
    (
        [id] => 122
        [name] => run batch B
    )
    

    XPath 教程:


    另一种方法是使用SimpleXmlIterator 来迭代元素。 Iterators 可以是 decorated 与其他迭代器,所以你可以这样做:

    class XmlFilterIterator extends FilterIterator
    {
        protected $filterElement;
        public function setFilterElement($name)
        {
            $this->filterElement = $name;
        }
        public function accept()
        {
            return ($this->current()->getName() === $this->filterElement);
        }
    }
    
    $sxi = new XmlFilterIterator(
               new RecursiveIteratorIterator( 
                   new SimpleXmlIterator($xml)));
    
    $sxi->setFilterElement('process');
    
    foreach($sxi as $el) {
        var_dump( $el ); // will only give process elements
    }
    

    您必须添加更多方法才能使过滤器对属性起作用,但这是一项相当简单的任务。

    SpliIterators 简介:

    【讨论】:

    • 非常感谢,第一个解决方案看起来不错,但我有一个错误:PHP 致命错误:未捕获异常“异常”,消息“字符串无法解析为 XML”。我像这样传递文件。 $xml = "/path/to/file.xml";这是正确的吗?
    • @Phill 不,它需要 XML 字符串,而不是文件路径。如果你想传递一个文件路径,你必须传递$data_is_url 作为第三个参数。见de3.php.net/manual/en/simplexmlelement.construct.php
    • @Phill 或将呼叫替换为simplexml_load_file
    • 嗯,做出了改变:$this->xml = new SimpleXMLElement($xml, NULL, TRUE);但仍然出现错误:PHP 致命错误:未捕获的异常 'Exception' 带有消息 'String 无法解析为 XML' 我在你的类示例中进行了更改,这是否正确?
    • "@Phill 或将调用替换为 simplexml_load_file" 替换在哪里?在构造函数中?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    • 2018-12-29
    • 2012-05-19
    相关资源
    最近更新 更多