private static function xmlToArray(
        \SimpleXMLElement $xml,
        $ns = null,
        $nesting = 0
    ) {
        $result = [];
        $children = $xml->children($ns, true);

        foreach ($children as $name => $child) {
            $attributes = (array) $child->attributes($ns, true);
            if (!isset($result[$name])) {
                $childArray = self::xmlToArray($child, $ns, $nesting + 1);
                $result[$name] = $attributes
                    ? array_merge($attributes, $childArray)
                    : $childArray;
                continue;
            }
            // A child element with this name exists so we're assuming
            // that the node contains a list of elements
            if (!is_array($result[$name])) {
                $result[$name] = [$result[$name]];
            } elseif (!isset($result[$name][0])) {
                // Convert the first child into the first element of a numerically indexed array
                $firstResult = $result[$name];
                $result[$name] = [];
                $result[$name][] = $firstResult;
            }
            $childArray = self::xmlToArray($child, $ns, $nesting + 1);
            if ($attributes) {
                $result[$name][] = array_merge($attributes, $childArray);
            } else {
                $result[$name][] = $childArray;
            }
        }

        // Extract text from node
        $text = trim((string) $xml);
        if ($text === '') {
            $text = null;
        }

        // Process attributes
        $attributes = (array) $xml->attributes($ns, true);
        if ($attributes) {
            if ($text !== null) {
                $result['value'] = $text;
            }
            $result = array_merge($attributes, $result);
        } elseif ($text !== null) {
            $result = $text;
        }

        // Make sure we're always returning an array
        if ($nesting == 0 && !is_array($result)) {
            $result = [$result];
        }

        return $result;
    }