Updated XML module from github

This commit is contained in:
Deon George 2012-07-12 15:10:39 +10:00
parent 326eb7bef3
commit 42c7f29665
7 changed files with 137 additions and 157 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2010 Cédric Cazettes
Copyright (c) 2010 Cédric de Saint Léger
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

View File

@ -1,11 +1,11 @@
Kohana_XML is a module used to generate and read XML documents in Kohana.
It is built for KO3, but there are barely one or two lines that makes it KO3 specific,
Kohana_XML is a XML modules to generate and read XML documents in Kohana.
It is build for KO3, but there are barely one or two lines that makes it KO3 specific,
so I guess it should work for KO2.x without much trouble.
## Notable Features
* **Extendible, configurable drivers** — You can use the XML class to write simple XML,
or use drivers to generate RFC-specific compliant XML (Atom/RSS2...), or write your own driver (extending XML
or use the Atom driver to generate Atom compliant XML, or write your own driver (extending XML
or another driver) to generate XML compliant to any specs you want. Driver support initial
configuration, which will be used when using native functions, and your own function.
Namespaces and prefix, value filters, default attributes, node name abstraction are all part

View File

@ -99,7 +99,7 @@
// Initialize the document with the given element
if (is_string($element))
{
if (is_file($element) OR valid::url($element))
if (is_file($element) OR Valid::url($element))
{
// Generate XML from a file
$this->dom_doc->load($element);
@ -124,14 +124,12 @@
elseif ( ! is_null($this->root_node))
{
// Create the Root Element from the driver attributes
if ($this->meta()->ns($this->root_node))
if ($this->meta()->get("namespace", $this->root_node))
{
list($ns, $prefix) = $this->meta()->ns($this->root_node);
$root_node_name = $prefix ? "$prefix:$this->root_node" : $this->root_node;
$root_node_name = $this->meta()->get("prefix", $this->root_node) ? $this->meta()->get("prefix", $this->root_node).":$this->root_node" : $this->root_node;
// Create the root node in its prefixed namespace
$root_node = $this->dom_doc->createElementNS($ns, $root_node_name);
$root_node = $this->dom_doc->createElementNS($this->meta()->get("namespace", $this->root_node), $root_node_name);
}
else
{
@ -174,7 +172,7 @@
// Add the value if provided
if ($value !== NULL)
{
$value = strval($this->filter($name, $value));
$value = strval($this->filter($name, $value, $node));
if (str_replace(array('<', '>', '&'), "", $value) === $value)
{
@ -358,10 +356,33 @@
{
// All other nodes shall be parsed normally : attributes then text value and child nodes, running through the XML tree
$object_element = array();
// Get the desired node name for this node
$node_name = $this->meta()->key($dom_node->tagName);
// Get children, run through XML tree
if ($dom_node->hasChildNodes())
{
if (!$dom_node->firstChild->hasChildNodes())
{
// Get text value
$object_element[$node_name] = trim($dom_node->firstChild->nodeValue);
}
foreach($dom_node->childNodes as $dom_child)
{
if ($dom_child->nodeType === XML_ELEMENT_NODE)
{
$child = $this->_as_array($dom_child);
foreach ($child as $key=>$val)
{
$object_element[$node_name][$key][]=$val;
}
}
}
}
// Get attributes
if ($dom_node->hasAttributes())
{
@ -370,38 +391,13 @@
{
// Get the desired name for this attribute
$att_name = $this->meta()->key($att_name);
$object_element[$node_name]['xml_attributes'][$att_name] = $dom_attribute->value;
}
}
// Get children, run through XML tree
if ($dom_node->hasChildNodes())
{
if (!$dom_node->firstChild->hasChildNodes())
{
// Get text value
$object_element[$node_name] = trim($dom_node->firstChild->nodeValue);
}
foreach($dom_node->childNodes as $dom_child)
{
if ($dom_child->nodeType === XML_ELEMENT_NODE)
{
$child = $this->_as_array($dom_child);
foreach ($child as $key=>$val)
{
$object_element[$node_name][$key][]=$val;
}
}
}
}
return $object_element;
}
/**
* Converts an array to XML. Expected structure is given in as_array().
* However, from_array() is essentially more flexible regarding to the input array structure,
@ -418,7 +414,6 @@
}
/**
* Array shall be like : array('element_name' => array( 0 => text, 'xml_attributes' => array()));
* @param object $mixed
@ -456,6 +451,10 @@
// Create a new element with the key as the element name.
// Create the element corresponding to the key
$node = $this->create_element($index);
// Add the driver attributes
$this->add_attributes($node);
// Append it
$dom_element->appendChild($node);
@ -464,14 +463,13 @@
}
}
}
else
elseif ($mixed)
{
// This is a string value that shall be appended as such
$mixed = $this->filter($dom_element->tagName, $mixed);
$mixed = $this->filter($dom_element->tagName, $mixed, $dom_element);
$dom_element->appendChild($this->dom_doc->createTextNode($mixed));
}
}
/**
@ -516,24 +514,26 @@
$name = $this->meta()->alias($name);
// Let's check if the element name has a namespace, and if this prefix is defined in our driver
if ($this->meta()->ns($name))
if ($namespace_uri = $this->meta()->get("namespace", $name))
{
list ($ns, $prefix) = $this->meta()->ns($name);
if ($prefix)
if (stristr($name, ":"))
{
// Separate the namespace prefix and the name
list($prefix, $name) = explode(":", $name);
// Register the prefixed namespace in the document root
$this->dom_doc->documentElement->setAttributeNS("http://www.w3.org/2000/xmlns/" ,"xmlns:$prefix", $ns);
$this->dom_doc->documentElement->setAttributeNS("http://www.w3.org/2000/xmlns/" ,"xmlns:".$prefix, $namespace_uri);
// Create the prefixed element within that namespace
$node = $this->dom_doc->createElementNS($ns, $name);
$node = $this->dom_doc->createElementNS($namespace_uri, $prefix.":".$name);
}
else
{
// Create the element normally
$node = $this->dom_doc->createElement($name);
// Add the new default namespace as an attribute.
$node->setAttribute("xmlns", $ns);
$node->setAttribute("xmlns", $namespace_uri);
}
}
else
@ -555,26 +555,30 @@
{
$node_name = $this->meta()->alias($node->tagName);
if ($this->meta()->attributes($node_name))
if ($this->meta()->get("attributes", $node_name))
{
$attributes = array_merge($this->meta()->attributes($node_name), $attributes);
$attributes = array_merge($this->meta()->get("attributes", $node_name), $attributes);
}
foreach ($attributes as $key => $val)
{
// Trim elements
$key = $this->meta()->alias(trim($key));
$val = $this->filter($key, trim($val));
$val = $this->filter($key, trim($val), $node);
// Set the attribute
// Let's check if the attribute name has a namespace prefix, and if this prefix is defined in our driver
if ($this->meta()->ns($key))
if ($namespace_uri = $this->meta()->get("namespace", $key)
AND stristr($name, ":"))
{
list ($ns, $prefix) = $this->meta()->ns($key);
// Separate the namespace prefix and the name
list($prefix, $name) = explode(":", $name);
// Register the prefixed namespace
$this->dom_node->setAttributeNS("http://www.w3.org/2000/xmlns/" ,"xmlns:$prefix", $ns);
$this->dom_node->setAttributeNS("http://www.w3.org/2000/xmlns/" ,"xmlns:".$prefix, $namespace_uri);
// Add the prefixed attribute within that namespace
$node->setAttributeNS($ns, $key, $val);
$node->setAttributeNS($namespace_uri, $key, $val);
}
else
{
@ -584,8 +588,7 @@
}
return $node;
}
/**
* Applies filter on a value.
@ -593,19 +596,19 @@
* They allow to format dates, links, standard stuff, and play
* as you wish with the value before it is added to the document.
*
* You could even extend it and modidy the node name.
* You could even extend it and modify the node name.
*
* @param string $name
* @param string $value
* @return string $value formatted value
*/
protected function filter($name, $value)
protected function filter($name, $value, &$node)
{
$name = $this->meta()->alias($name);
if ($this->meta()->filter($name))
if ($this->meta()->get("filter", $name))
{
return call_user_func(array($this, $this->meta()->filter($name)), $value);
return call_user_func(array($this, $this->meta()->get("filter", $name)), $value, $node);
}
return $value;
}
@ -616,10 +619,15 @@
* @param object $value
* @return $value
*/
public function normalize_uri($value)
public function normalize_uri($value, $node)
{
if (strpos($value, '://') === FALSE)
{
if (strlen(URL::base()) > 1 AND stristr($value, URL::base()))
{
// Make sure the path is not base related
$value = str_replace(URL::base(), '', $value);
}
// Convert URIs to URLs
$value = URL::site($value, TRUE);
}
@ -638,7 +646,6 @@
}
/**
* Returns this drivers XML metadata
* @return XML_Meta
@ -647,8 +654,7 @@
{
return XML::$_metas[strtolower(get_class($this))];
}
/**
* Outputs nicely formatted XML when converting as string
@ -660,7 +666,6 @@
}
/**
* Render the XML.
* @param boolean $formatted [optional] Should the output be formatted and indented ?

View File

@ -19,8 +19,9 @@ class XML_Driver_Atom extends XML
->nodes (
array(
"feed" => array("namespace" => "http://www.w3.org/2005/Atom"),
"entry" => array("namespace" => "http://www.w3.org/2005/Atom"),
// "entry" => array("namespace" => "http://www.w3.org/2005/Atom"),
"href" => array("filter" => "normalize_uri"),
"link" => array("filter" => "normalize_uri"),
"logo" => array("filter" => "normalize_uri"),
"icon" => array("filter" => "normalize_uri"),
"id" => array("filter" => "normalize_uri"),
@ -28,11 +29,15 @@ class XML_Driver_Atom extends XML
"published" => array("filter" => "normalize_datetime"),
"startDate" => array("filter" => "normalize_date"),
'endDate' => array("filter" => "normalize_date"),
"summary" => array("filter" => "normalize_text"),
"subtitle" => array("filter" => "normalize_text"),
"title" => array("filter" => "normalize_text"),
"content" => array("filter" => "normalize_text")
)
);
}
public function add_person($type, $name, $email = NULL, $uri = NULL)
{
$author = $this->add_node($type);
@ -47,8 +52,8 @@ class XML_Driver_Atom extends XML
}
return $this;
}
public function add_content(XML $xml_document)
{
$this->add_node("content", NULL, array("type" => $xml_document->meta()->content_type()))->import($xml_document);
@ -56,6 +61,21 @@ class XML_Driver_Atom extends XML
}
public function normalize_text($value, $node)
{
if (strpos($value, "<") >= 0 AND strpos($value, ">") > 0)
{
// Assume type = html
$node->setAttribute("type", "html");
}
else
{
$node->setAttribute("type", "text");
}
return $value;
}
public function normalize_datetime($value)
{
if ( ! is_numeric($value))
@ -66,7 +86,8 @@ class XML_Driver_Atom extends XML
// Convert timestamps to RFC 3339 formatted datetime
return date(DATE_RFC3339, $value);
}
public function normalize_date($value)
{
if ( ! is_numeric($value))
@ -77,32 +98,4 @@ class XML_Driver_Atom extends XML
// Convert timestamps to RFC 3339 formatted dates
return date("Y-m-d", $value);
}
public function render($formatted = FALSE)
{
if ( ! $this->published)
{
// Add the published node with current date
$this->add_node("published", time());
}
// Add the link to self
$this->add_node("link", NULL, array("rel" => "self", "href" => $_SERVER['REQUEST_URI']));
return parent::render($formatted);
}
public function export($file)
{
if ( ! $this->published)
{
// Add the published node with current date
$this->add_node("published", time());
}
// Add the link to self
$this->add_node("link", NULL, array("rel" => "self", "href" => $_SERVER['REQUEST_URI']));
parent::export($file);
}
}

View File

@ -18,15 +18,25 @@ class XML_Driver_Rss2 extends XML
->nodes (
array(
"rss" => array("attributes" => array("version" => "2.0")),
"title" => array("filter" => "normalize_text"),
"description" => array("filter" => "normalize_text"),
"link" => array("filter" => "normalize_uri"),
"atom:link" => array("attributes" => array(
"rel" => "self",
"type" => "application/rss+xml",
// "href" => URL::site(Request::initial()->uri(), TRUE)
),
"namespace" => "http://www.w3.org/2005/Atom"),
"href" => array("filter" => "normalize_uri"),
"docs" => array("filter" => "normalize_uri"),
"guid" => array("filter" => "normalize_uri"),
"pubDate" => array("filter" => "normalize_date"),
"lastBuildDate" => array("filter" => "normalize_date"),
"lastBuildDate" => array("filter" => "normalize_date")
)
);
}
public function normalize_date($value)
{
if ( ! is_numeric($value))
@ -34,7 +44,14 @@ class XML_Driver_Rss2 extends XML
$value = strtotime($value);
}
// Convert timestamps to RFC 822 formatted dates
return date(DATE_RFC822, $value);
// Convert timestamps to RFC 822 formatted dates, with 4 digits year
return date(DATE_RSS, $value);
}
public function normalize_text($value)
{
// Strip HTML tags
return strip_tags($value);
}
}

View File

@ -8,19 +8,18 @@
* XRDS driver. For Service Discovery.
*/
class XML_Driver_XRDS extends XML
{
public $root_node = 'XRDS';
class XML_Driver_XRDS extends XML
{
public $root_node = 'xrds:XRDS';
protected static function initialize(XML_Meta $meta)
{
$meta ->content_type("application/xrds+xml")
->nodes (
array(
"XRDS" => array("namespace" => 'xri://$xrds', "prefix" => "xrds", "attributes" => array("xmlns" => 'xri://$xrd*($v*2.0)')),
"xrds:XRDS" => array("namespace" => 'xri://$xrds', "attributes" => array("xmlns" => 'xri://$xrd*($v*2.0)')),
"LocalID" => array("filter" => "normalize_uri"),
"Delegate" => array("filter" => "normalize_uri", "namespace" => "http://openid.net/xmlns/1.0", "prefix" => "openid"),
"openid:Delegate" => array("filter" => "normalize_uri", "namespace" => "http://openid.net/xmlns/1.0"),
"URI" => array("filter" => "normalize_uri"),
)
);
@ -53,5 +52,4 @@
return $service_node;
}
}

View File

@ -47,7 +47,6 @@
protected $_initialized = FALSE;
/**
* Returns the name of a node, sort out aliases
* @param string $name
@ -66,53 +65,21 @@
return Arr::get($this->nodes, $name, $name);
}
/**
* Return namespace config for a given node
* @param string $name
* @return mixed array(uri, prefix) or NULL
* Returns the value of a meta key for a given node name
* exemple $this->get('attributes', 'feed') will return all the attributes set up in the meta
* for the node feed.
* @param object $key meta key
* @param object $name node name
* @return meta value or NULL if not set
*/
public function ns($name)
public function get($key, $name)
{
$name = $this->alias($name);
if (isset($this->nodes_config[$name]) AND is_array($this->nodes_config[$name]) AND array_key_exists("namespace", $this->nodes_config[$name]))
if (isset($this->nodes_config[$name]) AND is_array($this->nodes_config[$name]) AND array_key_exists($key, $this->nodes_config[$name]))
{
return array($this->nodes_config[$name]["namespace"], Arr::get($this->nodes_config[$name], "prefix", NULL));
}
return NULL;
}
/**
* Return default attributes for a given node
* @param string $name
* @return mixed attributes assoc array() or NULL
*/
public function attributes($name)
{
$name = $this->alias($name);
if (isset($this->nodes_config[$name]) AND is_array($this->nodes_config[$name]) AND array_key_exists("attributes", $this->nodes_config[$name]))
{
return $this->nodes_config[$name]["attributes"];
}
return NULL;
}
/**
* Return user-defined value filter function for a given node
* @param string $name
* @return mixed function name or NULL
*/
public function filter($name)
{
$name = $this->alias($name);
if (isset($this->nodes_config[$name]) AND is_array($this->nodes_config[$name]) AND array_key_exists("filter", $this->nodes_config[$name]))
{
return $this->nodes_config[$name]["filter"];
return $this->nodes_config[$name][$key];
}
return NULL;
}