skip to Main Content

i want to parse xml files.
Its for an importer, where you can define a configuration

My Problem is, that the xml parser (SimpleXml & Dom) did it inconstistence.

When i only have one child node – it will give me a simpleXML

<sizes>
    <size>
        <gpp>   5,00</gpp>
        <gppcurrency>EUR</gppcurrency>
        <npp>   5,00</npp>
        <nppcurrency>EUR</nppcurrency>
        <sp>   5,00</sp>
        <spcurrency>EUR</spcurrency>
        <stock>100</stock>
    </size>
</sizes>

Will be

sizes [SimpleXmlElement]
 => size [SimpleXmlElement]
    - gpp
    - gppcurrency 
    ...

BUT if i have multiple nodes

<sizes>
    <size>
        <gpp>   5,00</gpp>
        <gppcurrency>EUR</gppcurrency>
        <npp>   5,00</npp>
        <nppcurrency>EUR</nppcurrency>
        <sp>   5,00</sp>
        <spcurrency>EUR</spcurrency>
        <stock>100</stock>
    </size>
    <size>
        <gpp>   5,00</gpp>
        <gppcurrency>EUR</gppcurrency>
        <npp>   5,00</npp>
        <nppcurrency>EUR</nppcurrency>
        <sp>   5,00</sp>
        <spcurrency>EUR</spcurrency>
        <stock>100</stock>
    </size>
</sizes>

It will output

sizes [SimpleXmlElement]
 => size array
   [0] [SimpleXmlElement]
      - gpp
      - gppcurrency 
      ...
   [1] [SimpleXmlElement]
      - gpp
      - gppcurrency 
      ...

This is realy incosistent and may you can help me find an answer for this.
Thanks

2

Answers


  1. Chosen as BEST ANSWER

    I have found my solution to consistencly get an array.

    <?php
    
    declare(strict_types=1);
    
    namespace srcImExportFormatter;
    
    use SimpleXMLElement;
    
    class XmlToArrayFormatter
    {
        public function parseXmlToArray(SimpleXmlElement $xml, $collection = [])
        {
            $childNodes = $xml->children();
    
            if (0 === $childNodes->count()) {
                if (empty($xml)) {
                    return false;
                }
    
                return strval($xml);
            }
            $currentNodeAsArray = false;
            if ($this->getNodeLevel($xml) > 0 &&
                $this->hasOnlySubNodes($xml) &&
                !is_string($xml)) {
                $currentNodeAsArray = true;
            }
    
            foreach ($childNodes as $nodeName => $nodeValue) {
                $xmlArray = $this->parseXmlToArray($nodeValue);
                if ($currentNodeAsArray) {
                    $collection[$nodeName][] = $xmlArray;
                } else {
                    if ($xmlArray !== false) {
                        $collection[$nodeName] = $xmlArray;
                    }
                }
            }
    
            return $collection;
        }
    
        protected function getNodeLevel(?SimpleXMLElement $parentNodes, $level = 0): int
        {
            if (is_null($parentNodes)) {
                return $level;
            }
    
            if (count($parentNodes->children())) {
                $level++;
            }
    
            foreach ($parentNodes->children() as $parentNodeValues) {
                $level = $this->getNodeLevel($parentNodeValues, $level);
            }
    
            return $level;
        }
    
        public function hasOnlySubNodes(?SimpleXMLElement $node): bool
        {
            foreach ($node->children() as $nodeValues) {
                if (count($nodeValues->children()) == 0 && !empty(strval($nodeValues))) {
                    return false;
                }
            }
    
            return true;
        }
    }
    

  2. Whether or not the internal pieces use an array does not matter. What is being returned is a SimpleXMLElement object (not a bare array) with getters that will return an iterable value in either case. The array you are seeing is how the value is stored within the SimpleXMLElement, but it will handle converting a single child item to an iterable value when you access it.

    foreach($singleNode->size as $size) {
        var_dump($size);
    }
    // object(SimpleXMLElement) { ["gpp"] ... }
    
    foreach($multiNode->size as $size) {
        var_dump($size);
    }
    // object(SimpleXMLElement) { ["gpp"] ... }
    // object(SimpleXMLElement) { ["gpp"] ... }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search