<?PHP

require_once "Auth/Yadis/XML.php";

/**
 * This concrete implementation of Auth_Yadis_XMLParser implements
 * the appropriate API for the 'simplexml' extension which is typically
 * packaged with PHP 5.  This class will be used whenever the 'simplexml'
 * extension is detected.  See the Auth_Yadis_XMLParser class for
 * details on this class's methods.
 *
 * @package OpenID
 */
class Auth_Yadis_simplexml extends Auth_Yadis_XMLParser
{

    /**
     * Parse the given XML string.
     * @param $Xml XML string
     * @return TRUE if parsing is successful, FALSE otherwise
     */
    public function setXML($Xml)
    {
        $this->Xml = $Xml;
        $this->Document = @simplexml_load_string($Xml);

        # failed to parse the XML string
        if (FALSE === $this->Document)
        {
            return FALSE;
        }

        return TRUE;
    }

    /**
     * Register the given XPath namespace.
     * @param $Prefix namespace prefix for element names
     * @param $Uri namespace/namespace URI
     * @return TRUE if successful, FALSE otherwise
     */
    public function registerNamespace($Prefix, $Uri)
    {
        $this->XpathNamespaces[$Prefix] = $Uri;
        $Result = $this->Document->registerXPathNamespace($Prefix, $Uri);

        return $Result;
    }

    /**
     * Evaluate the given XPath query.
     * @param $Xpath XPath query
     * @param $Node optional scope as a SimpleXMLElement object
     * @return an array of SimpleXMLElement objects that match the query
     */
    public function &evalXPath($Xpath, $Node=NULL)
    {
        # scope in which to search
        if ($Node instanceof SimpleXMLElement)
        {
            # since XPath namespaces on the document are carried through to
            # child nodes, they need to be applied here
            foreach ($this->XpathNamespaces as $Prefix => $Uri)
            {
                $Node->registerXPathNamespace($Prefix, $Uri);
            }

            $Result = $Node->xpath($Xpath);
        }

        else
        {
            $Result = $this->Document->xpath($Xpath);
        }

        $Nodes = array();

        if (FALSE === $Result)
        {
            return $Nodes;
        }

        # add found nodes
        while(list(, $Node) = each($Result))
        {
            $Nodes[] = $Node;
        }

        return $Nodes;
    }

    /**
     * Get the content of the XML node as a string.
     * @param $Node SimpleXMLElement object
     * @return the content of the XML node as a string
     */
    public function content($Node)
    {
        # only work with SimpleXMLElement objects
        if (!($Node instanceof SimpleXMLElement))
        {
            return NULL;
        }

        return "$Node";
    }

    /**
     * Get the attributes of the given node.
     * @param $Node SimpleXMLElement object
     * @return an array of the object's attributes
     */
    public function attributes($Node)
    {
        $Attributes = array();

        # only work with SimpleXMLElement objects
        if (!($Node instanceof SimpleXMLElement))
        {
            return $Attributes;
        }

        $AttributeObjects = $Node->attributes();

        # the node is an attribute and not an element
        if (is_null($AttributeObjects))
        {
            return $Attributes;
        }

        # add each attribute and its value
        foreach ($AttributeObjects as $Name => $Value)
        {
            $Attributes["$Name"] = "$Value";
        }

        return $Attributes;
    }

    /**
     * @var $Xml XML string
     * @var $Document SimpleXMLElement representing the XML document
     * @var $XpathNamespaces XPath namespace cache for XPath Queries
     */
    private $Xml;
    private $Document;
    private $XpathNamespaces;

}
