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 Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation 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. Kohana_XML is a XML modules 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, 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. so I guess it should work for KO2.x without much trouble.
## Notable Features ## Notable Features
* **Extendible, configurable drivers** — You can use the XML class to write simple XML, * **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 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. 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 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 // Initialize the document with the given element
if (is_string($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 // Generate XML from a file
$this->dom_doc->load($element); $this->dom_doc->load($element);
@ -124,14 +124,12 @@
elseif ( ! is_null($this->root_node)) elseif ( ! is_null($this->root_node))
{ {
// Create the Root Element from the driver attributes // 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 = $this->meta()->get("prefix", $this->root_node) ? $this->meta()->get("prefix", $this->root_node).":$this->root_node" : $this->root_node;
$root_node_name = $prefix ? "$prefix:$this->root_node" : $this->root_node;
// Create the root node in its prefixed namespace // 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 else
{ {
@ -174,7 +172,7 @@
// Add the value if provided // Add the value if provided
if ($value !== NULL) if ($value !== NULL)
{ {
$value = strval($this->filter($name, $value)); $value = strval($this->filter($name, $value, $node));
if (str_replace(array('<', '>', '&'), "", $value) === $value) if (str_replace(array('<', '>', '&'), "", $value) === $value)
{ {
@ -362,19 +360,6 @@
// Get the desired node name for this node // Get the desired node name for this node
$node_name = $this->meta()->key($dom_node->tagName); $node_name = $this->meta()->key($dom_node->tagName);
// Get attributes
if ($dom_node->hasAttributes())
{
$object_element[$dom_node->nodeName]['xml_attributes'] = array();
foreach($dom_node->attributes as $att_name => $dom_attribute)
{
// 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 // Get children, run through XML tree
if ($dom_node->hasChildNodes()) if ($dom_node->hasChildNodes())
{ {
@ -397,11 +382,22 @@
} }
} }
} }
// Get attributes
if ($dom_node->hasAttributes())
{
$object_element[$dom_node->nodeName]['xml_attributes'] = array();
foreach($dom_node->attributes as $att_name => $dom_attribute)
{
// 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;
}
}
return $object_element; return $object_element;
} }
/** /**
* Converts an array to XML. Expected structure is given in as_array(). * 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, * 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())); * Array shall be like : array('element_name' => array( 0 => text, 'xml_attributes' => array()));
* @param object $mixed * @param object $mixed
@ -456,6 +451,10 @@
// Create a new element with the key as the element name. // Create a new element with the key as the element name.
// Create the element corresponding to the key // Create the element corresponding to the key
$node = $this->create_element($index); $node = $this->create_element($index);
// Add the driver attributes
$this->add_attributes($node);
// Append it // Append it
$dom_element->appendChild($node); $dom_element->appendChild($node);
@ -464,16 +463,15 @@
} }
} }
} }
else elseif ($mixed)
{ {
// This is a string value that shall be appended as such // 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)); $dom_element->appendChild($this->dom_doc->createTextNode($mixed));
} }
} }
/** /**
* This function is used to import another XML instance, or whatever we can construct XML from (string, filename, DOMNode...) * This function is used to import another XML instance, or whatever we can construct XML from (string, filename, DOMNode...)
* *
@ -516,24 +514,26 @@
$name = $this->meta()->alias($name); $name = $this->meta()->alias($name);
// Let's check if the element name has a namespace, and if this prefix is defined in our driver // 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 (stristr($name, ":"))
if ($prefix)
{ {
// Separate the namespace prefix and the name
list($prefix, $name) = explode(":", $name);
// Register the prefixed namespace in the document root // 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 // Create the prefixed element within that namespace
$node = $this->dom_doc->createElementNS($ns, $name); $node = $this->dom_doc->createElementNS($namespace_uri, $prefix.":".$name);
} }
else else
{ {
// Create the element normally // Create the element normally
$node = $this->dom_doc->createElement($name); $node = $this->dom_doc->createElement($name);
// Add the new default namespace as an attribute. // Add the new default namespace as an attribute.
$node->setAttribute("xmlns", $ns); $node->setAttribute("xmlns", $namespace_uri);
} }
} }
else else
@ -555,26 +555,30 @@
{ {
$node_name = $this->meta()->alias($node->tagName); $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) foreach ($attributes as $key => $val)
{ {
// Trim elements // Trim elements
$key = $this->meta()->alias(trim($key)); $key = $this->meta()->alias(trim($key));
$val = $this->filter($key, trim($val)); $val = $this->filter($key, trim($val), $node);
// Set the attribute // Set the attribute
// Let's check if the attribute name has a namespace prefix, and if this prefix is defined in our driver // 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 // 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 // Add the prefixed attribute within that namespace
$node->setAttributeNS($ns, $key, $val); $node->setAttributeNS($namespace_uri, $key, $val);
} }
else else
{ {
@ -586,26 +590,25 @@
} }
/** /**
* Applies filter on a value. * Applies filter on a value.
* These filters are callbacks usually defined in the driver. * These filters are callbacks usually defined in the driver.
* They allow to format dates, links, standard stuff, and play * They allow to format dates, links, standard stuff, and play
* as you wish with the value before it is added to the document. * 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 $name
* @param string $value * @param string $value
* @return string $value formatted value * @return string $value formatted value
*/ */
protected function filter($name, $value) protected function filter($name, $value, &$node)
{ {
$name = $this->meta()->alias($name); $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; return $value;
} }
@ -616,10 +619,15 @@
* @param object $value * @param object $value
* @return $value * @return $value
*/ */
public function normalize_uri($value) public function normalize_uri($value, $node)
{ {
if (strpos($value, '://') === FALSE) 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 // Convert URIs to URLs
$value = URL::site($value, TRUE); $value = URL::site($value, TRUE);
} }
@ -638,7 +646,6 @@
} }
/** /**
* Returns this drivers XML metadata * Returns this drivers XML metadata
* @return XML_Meta * @return XML_Meta
@ -649,7 +656,6 @@
} }
/** /**
* Outputs nicely formatted XML when converting as string * Outputs nicely formatted XML when converting as string
* @return string * @return string
@ -660,7 +666,6 @@
} }
/** /**
* Render the XML. * Render the XML.
* @param boolean $formatted [optional] Should the output be formatted and indented ? * @param boolean $formatted [optional] Should the output be formatted and indented ?

View File

@ -19,8 +19,9 @@ class XML_Driver_Atom extends XML
->nodes ( ->nodes (
array( array(
"feed" => array("namespace" => "http://www.w3.org/2005/Atom"), "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"), "href" => array("filter" => "normalize_uri"),
"link" => array("filter" => "normalize_uri"),
"logo" => array("filter" => "normalize_uri"), "logo" => array("filter" => "normalize_uri"),
"icon" => array("filter" => "normalize_uri"), "icon" => array("filter" => "normalize_uri"),
"id" => array("filter" => "normalize_uri"), "id" => array("filter" => "normalize_uri"),
@ -28,6 +29,10 @@ class XML_Driver_Atom extends XML
"published" => array("filter" => "normalize_datetime"), "published" => array("filter" => "normalize_datetime"),
"startDate" => array("filter" => "normalize_date"), "startDate" => array("filter" => "normalize_date"),
'endDate' => 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")
) )
); );
} }
@ -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) public function normalize_datetime($value)
{ {
if ( ! is_numeric($value)) if ( ! is_numeric($value))
@ -67,6 +87,7 @@ class XML_Driver_Atom extends XML
return date(DATE_RFC3339, $value); return date(DATE_RFC3339, $value);
} }
public function normalize_date($value) public function normalize_date($value)
{ {
if ( ! is_numeric($value)) if ( ! is_numeric($value))
@ -77,32 +98,4 @@ class XML_Driver_Atom extends XML
// Convert timestamps to RFC 3339 formatted dates // Convert timestamps to RFC 3339 formatted dates
return date("Y-m-d", $value); 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 ( ->nodes (
array( array(
"rss" => array("attributes" => array("version" => "2.0")), "rss" => array("attributes" => array("version" => "2.0")),
"title" => array("filter" => "normalize_text"),
"description" => array("filter" => "normalize_text"),
"link" => array("filter" => "normalize_uri"), "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"), "docs" => array("filter" => "normalize_uri"),
"guid" => array("filter" => "normalize_uri"), "guid" => array("filter" => "normalize_uri"),
"pubDate" => array("filter" => "normalize_date"), "pubDate" => array("filter" => "normalize_date"),
"lastBuildDate" => array("filter" => "normalize_date"), "lastBuildDate" => array("filter" => "normalize_date")
) )
); );
} }
public function normalize_date($value) public function normalize_date($value)
{ {
if ( ! is_numeric($value)) if ( ! is_numeric($value))
@ -34,7 +44,14 @@ class XML_Driver_Rss2 extends XML
$value = strtotime($value); $value = strtotime($value);
} }
// Convert timestamps to RFC 822 formatted dates // Convert timestamps to RFC 822 formatted dates, with 4 digits year
return date(DATE_RFC822, $value); 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. * XRDS driver. For Service Discovery.
*/ */
class XML_Driver_XRDS extends XML class XML_Driver_XRDS extends XML
{ {
public $root_node = 'XRDS'; public $root_node = 'xrds:XRDS';
protected static function initialize(XML_Meta $meta) protected static function initialize(XML_Meta $meta)
{ {
$meta ->content_type("application/xrds+xml") $meta ->content_type("application/xrds+xml")
->nodes ( ->nodes (
array( 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"), "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"), "URI" => array("filter" => "normalize_uri"),
) )
); );
@ -53,5 +52,4 @@
return $service_node; return $service_node;
} }
} }

View File

@ -47,7 +47,6 @@
protected $_initialized = FALSE; protected $_initialized = FALSE;
/** /**
* Returns the name of a node, sort out aliases * Returns the name of a node, sort out aliases
* @param string $name * @param string $name
@ -66,53 +65,21 @@
return Arr::get($this->nodes, $name, $name); return Arr::get($this->nodes, $name, $name);
} }
/** /**
* Return namespace config for a given node * Returns the value of a meta key for a given node name
* @param string $name * exemple $this->get('attributes', 'feed') will return all the attributes set up in the meta
* @return mixed array(uri, prefix) or NULL * 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); $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 $this->nodes_config[$name][$key];
}
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 NULL; return NULL;
} }