فهرست منبع

Zend_Feed_Writer: Made changes to implement relevant entity encoding as appropriate to RSS or Atom elements.

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@19789 44c647ce-9c0f-0410-b52a-842ac1e357ba
padraic 16 سال پیش
والد
کامیت
14d88cc42f

+ 0 - 33
library/Zend/Feed/Writer.php

@@ -257,38 +257,5 @@ class Zend_Feed_Writer
         self::registerExtension('Threading');
         self::registerExtension('ITunes');
     }
-    
-    /**
-     * Replaces XML special characters with entities. This is a generally
-     * safe XML encoding targeting the <, > and & characters. Quotes are
-     * left unencoded. It is not suitable for RSS 2.0 character data.
-     *
-     * @param string $string
-     * @param string $encoding
-     * @return string
-     */
-    public static function xmlentities($string, $encoding)
-    {
-        return htmlspecialchars($string, ENT_NOQUOTES, $encoding);
-    }
-    
-    /**
-     * Replaces the characters <, > and & with hexadecimal entities as
-     * recommended for textual character data not representing HTML in RSS 2.0.
-     * Per the published RSS Best Practices Profile this attempts to maximise
-     * compatibility with various feed parsers/readers.
-     *
-     * @param string $string
-     * @param string $encoding
-     * @return string
-     */
-    public static function textentities($string, $encoding)
-    {
-        return str_replace(
-            array('&amp;', '&lt;', '&gt;'),
-            array('&#x26;', '&#x3C;', '&#x3E;'),
-            htmlspecialchars($string, ENT_NOQUOTES, $encoding)
-        );
-    }
 
 }

+ 54 - 0
library/Zend/Feed/Writer/Entry.php

@@ -532,6 +532,60 @@ class Zend_Feed_Writer_Entry
     }
     
     /**
+     * Add a entry category
+     *
+     * @param string $category
+     */ 
+    public function addCategory(array $category)
+    {
+        if (!isset($category['term'])) {
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Each category must be an array and '
+            . 'contain at least a "term" element containing the machine '
+            . ' readable category name');
+        }
+        if (isset($category['scheme'])) {
+            if (empty($category['scheme']) 
+                || !is_string($category['scheme'])
+                || !Zend_Uri::check($category['scheme'])
+            ) {
+                require_once 'Zend/Feed/Exception.php';
+                throw new Zend_Feed_Exception('The Atom scheme or RSS domain of'
+                . ' a category must be a valid URI');
+            }
+        }
+        if (!isset($this->_data['categories'])) {
+            $this->_data['categories'] = array();
+        }
+        $this->_data['categories'][] = $category;
+    }
+    
+    /**
+     * Set an array of entry categories
+     *
+     * @param array $categories
+     */
+    public function addCategories(array $categories)
+    {
+        foreach ($categories as $category) {
+            $this->addCategory($category);
+        }
+    }
+    
+    /**
+     * Get the entry categories
+     *
+     * @return string|null
+     */
+    public function getCategories()
+    {
+        if (!array_key_exists('categories', $this->_data)) {
+            return null;
+        }
+        return $this->_data['categories'];
+    }
+    
+    /**
      * Adds an enclosure to the entry.
      *
      * @param array $enclosures

+ 2 - 5
library/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php

@@ -73,10 +73,7 @@ class Zend_Feed_Writer_Extension_Content_Renderer_Entry
         }
         $element = $dom->createElement('content:encoded');
         $root->appendChild($element);
-        $element->nodeValue = htmlentities(
-            $this->getDataContainer()->getContent(),
-            ENT_QUOTES,
-            $this->getDataContainer()->getEncoding()
-        );
+        $cdata = $dom->createCDATASection($content);
+        $element->appendChild($cdata);
     }
 }

+ 2 - 1
library/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php

@@ -74,7 +74,8 @@ class Zend_Feed_Writer_Extension_DublinCore_Renderer_Entry
         foreach ($authors as $data) {
             $author = $this->_dom->createElement('dc:creator');
             if (array_key_exists('name', $data)) {
-                $author->nodeValue = $data['name'];
+                $text = $dom->createTextNode($data['name']);
+                $author->appendChild($text);
                 $root->appendChild($author);   
             }
         }

+ 3 - 2
library/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php

@@ -74,8 +74,9 @@ class Zend_Feed_Writer_Extension_DublinCore_Renderer_Feed
         foreach ($authors as $data) {
             $author = $this->_dom->createElement('dc:creator');
             if (array_key_exists('name', $data)) {
-                $author->nodeValue = $data['name'];
-                $root->appendChild($author);   
+                $text = $dom->createTextNode($data['name']);
+                $author->appendChild($text);
+                $root->appendChild($author);  
             }
         }
     }

+ 14 - 15
library/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php

@@ -76,9 +76,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
         }
         foreach ($authors as $author) {
             $el = $dom->createElement('itunes:author');
-            $el->nodeValue = Zend_Feed_Writer::xmlentities(
-                $author, $this->getEncoding()
-            );
+            $text = $dom->createTextNode($author);
+            $el->appendChild($text);
             $root->appendChild($el);
         }
     }
@@ -97,7 +96,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
             return;
         }
         $el = $dom->createElement('itunes:block');
-        $el->nodeValue = $block;
+        $text = $dom->createTextNode($block);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -115,7 +115,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
             return;
         }
         $el = $dom->createElement('itunes:duration');
-        $el->nodeValue = $duration;
+        $text = $dom->createTextNode($duration);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -133,7 +134,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
             return;
         }
         $el = $dom->createElement('itunes:explicit');
-        $el->nodeValue = $explicit;
+        $text = $dom->createTextNode($explicit);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -151,9 +153,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
             return;
         }
         $el = $dom->createElement('itunes:keywords');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            implode(',', $keywords), $this->getEncoding()
-        );
+        $text = $dom->createTextNode(implode(',', $keywords));
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -171,9 +172,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
             return;
         }
         $el = $dom->createElement('itunes:subtitle');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            $subtitle, $this->getEncoding()
-        );
+        $text = $dom->createTextNode($subtitle);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -191,9 +191,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry
             return;
         }
         $el = $dom->createElement('itunes:summary');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            $summary, $this->getEncoding()
-        );
+        $text = $dom->createTextNode($summary);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
 }

+ 20 - 24
library/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php

@@ -80,9 +80,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
         }
         foreach ($authors as $author) {
             $el = $dom->createElement('itunes:author');
-            $el->nodeValue = Zend_Feed_Writer::xmlentities(
-                $author, $this->getEncoding()
-            );
+            $text = $dom->createTextNode($author);
+            $el->appendChild($text);
             $root->appendChild($el);
         }
     }
@@ -101,7 +100,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:block');
-        $el->nodeValue = $block;
+        $text = $dom->createTextNode($block);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -174,7 +174,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:duration');
-        $el->nodeValue = $duration;
+        $text = $dom->createTextNode($duration);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -192,7 +193,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:explicit');
-        $el->nodeValue = $explicit;
+        $text = $dom->createTextNode($explicit);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -210,9 +212,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:keywords');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            implode(',', $keywords), $this->getEncoding()
-        );
+        $text = $dom->createTextNode(implode(',', $keywords));
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -230,9 +231,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:new-feed-url');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            $url, $this->getEncoding()
-        );
+        $text = $dom->createTextNode($url);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -252,13 +252,11 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
         foreach ($owners as $owner) {
             $el = $dom->createElement('itunes:owner');
             $name = $dom->createElement('itunes:name');
-            $name->nodeValue = Zend_Feed_Writer::xmlentities(
-                $owner['name'], $this->getEncoding()
-            );
+            $text = $dom->createTextNode($owner['name']);
+            $name->appendChild($text);
             $email = $dom->createElement('itunes:email');
-            $email->nodeValue = Zend_Feed_Writer::xmlentities(
-                $owner['email'], $this->getEncoding()
-            );
+            $text = $dom->createTextNode($owner['email']);
+            $email->appendChild($text);
             $root->appendChild($el);
             $el->appendChild($name);
             $el->appendChild($email);
@@ -279,9 +277,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:subtitle');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            $subtitle, $this->getEncoding()
-        );
+        $text = $dom->createTextNode($subtitle);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
     
@@ -299,9 +296,8 @@ class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed
             return;
         }
         $el = $dom->createElement('itunes:summary');
-        $el->nodeValue = Zend_Feed_Writer::xmlentities(
-            $summary, $this->getEncoding()
-        );
+        $text = $dom->createTextNode($summary);
+        $el->appendChild($text);
         $root->appendChild($el);
     }
 }

+ 2 - 1
library/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php

@@ -74,7 +74,8 @@ class Zend_Feed_Writer_Extension_WellFormedWeb_Renderer_Entry
         foreach ($links as $link) {
             if ($link['type'] == 'rss') {
                 $flink = $this->_dom->createElement('wfw:commentRss');
-                $flink->nodeValue = $link['uri'];
+                $text = $dom->createTextNode($link['uri']);
+                $flink->appendChild($text);
                 $root->appendChild($flink);
             }
         }

+ 47 - 10
library/Zend/Feed/Writer/Renderer/Entry/Atom.php

@@ -66,6 +66,7 @@ class Zend_Feed_Writer_Renderer_Entry_Atom
         $this->_setAuthors($this->_dom, $entry);
         $this->_setEnclosure($this->_dom, $entry);
         $this->_setContent($this->_dom, $entry);
+        $this->_setCategories($this->_dom, $entry);
 
         foreach ($this->_extensions as $ext) {
             $ext->setType($this->getType());
@@ -150,8 +151,10 @@ class Zend_Feed_Writer_Renderer_Entry_Atom
 
         $updated = $dom->createElement('updated');
         $root->appendChild($updated);
-        $updated->nodeValue = $this->getDataContainer()->getDateModified()
-            ->get(Zend_Date::ISO_8601);
+        $text = $dom->createTextNode(
+            $this->getDataContainer()->getDateModified()->get(Zend_Date::ISO_8601)
+        );
+        $updated->appendChild($text);
     }
     
     /**
@@ -166,10 +169,12 @@ class Zend_Feed_Writer_Renderer_Entry_Atom
         if (!$this->getDataContainer()->getDateCreated()) {
             return;
         }
-        $updated = $dom->createElement('published');
-        $root->appendChild($updated);
-        $updated->nodeValue = $this->getDataContainer()->getDateCreated()
-            ->get(Zend_Date::ISO_8601);
+        $el = $dom->createElement('published');
+        $root->appendChild($el);
+        $text = $dom->createTextNode(
+            $this->getDataContainer()->getDateCreated()->get(Zend_Date::ISO_8601)
+        );
+        $el->appendChild($text);
     }
     
     /**
@@ -194,16 +199,19 @@ class Zend_Feed_Writer_Renderer_Entry_Atom
             $name = $this->_dom->createElement('name');
             $author->appendChild($name);
             $root->appendChild($author);
-            $name->nodeValue = $data['name'];
+            $text = $dom->createTextNode($data['name']);
+            $name->appendChild($text);
             if (array_key_exists('email', $data)) {
                 $email = $this->_dom->createElement('email');
                 $author->appendChild($email);
-                $email->nodeValue = $data['email'];
+                $text = $dom->createTextNode($data['email']);
+                $email->appendChild($text);
             }
             if (array_key_exists('uri', $data)) {
                 $uri = $this->_dom->createElement('uri');
                 $author->appendChild($uri);
-                $uri->nodeValue = $data['uri'];
+                $text = $dom->createTextNode($data['uri']);
+                $uri->appendChild($text);
             }
         }
     }
@@ -277,7 +285,8 @@ class Zend_Feed_Writer_Renderer_Entry_Atom
         }
         $id = $dom->createElement('id');
         $root->appendChild($id);
-        $id->nodeValue = $this->getDataContainer()->getId();
+        $text = $dom->createTextNode($this->getDataContainer()->getId());
+        $id->appendChild($text);
     }
     
     /**
@@ -310,4 +319,32 @@ class Zend_Feed_Writer_Renderer_Entry_Atom
         $element->appendChild($cdata);
         $root->appendChild($element);
     }
+    
+    /**
+     * Set entry cateories 
+     * 
+     * @param  DOMDocument $dom 
+     * @param  DOMElement $root 
+     * @return void
+     */
+    protected function _setCategories(DOMDocument $dom, DOMElement $root)
+    {
+        $categories = $this->getDataContainer()->getCategories();
+        if (!$categories) {
+            return;
+        }
+        foreach ($categories as $cat) {
+            $category = $dom->createElement('category');
+            $category->setAttribute('term', $cat['term']);
+            if (isset($cat['label'])) {
+                $category->setAttribute('label', $cat['label']);
+            } else {
+                $category->setAttribute('label', $cat['term']);
+            }
+            if (isset($cat['scheme'])) {
+                $category->setAttribute('scheme', $cat['scheme']);
+            }
+            $root->appendChild($category);
+        }
+    }
 }

+ 42 - 16
library/Zend/Feed/Writer/Renderer/Entry/Rss.php

@@ -54,6 +54,7 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
     {
         $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding());
         $this->_dom->formatOutput = true;
+        $this->_dom->substituteEntities = false;
         $entry = $this->_dom->createElement('item');
         $this->_dom->appendChild($entry);
         
@@ -66,6 +67,7 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
         $this->_setAuthors($this->_dom, $entry);
         $this->_setEnclosure($this->_dom, $entry);
         $this->_setCommentLink($this->_dom, $entry);
+        $this->_setCategories($this->_dom, $entry);
         foreach ($this->_extensions as $ext) {
             $ext->setType($this->getType());
             $ext->setRootElement($this->getRootElement());
@@ -101,11 +103,8 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
         }
         $title = $dom->createElement('title');
         $root->appendChild($title);
-        $title->nodeValue = htmlentities(
-            $this->getDataContainer()->getTitle(),
-            ENT_QUOTES,
-            $this->getDataContainer()->getEncoding()
-        );
+        $text = $dom->createTextNode($this->getDataContainer()->getTitle());
+        $title->appendChild($text);
     }
     
     /**
@@ -134,11 +133,8 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
         }
         $subtitle = $dom->createElement('description');
         $root->appendChild($subtitle);
-        $subtitle->nodeValue = htmlentities(
-            $this->getDataContainer()->getDescription(),
-            ENT_QUOTES,
-            $this->getDataContainer()->getEncoding()
-        );
+        $text = $dom->createCDATASection($this->getDataContainer()->getDescription());
+        $subtitle->appendChild($text);
     }
     
     /**
@@ -156,8 +152,10 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
 
         $updated = $dom->createElement('pubDate');
         $root->appendChild($updated);
-        $updated->nodeValue = $this->getDataContainer()->getDateModified()
-            ->get(Zend_Date::RSS);
+        $text = $dom->createTextNode(
+            $this->getDataContainer()->getDateModified()->get(Zend_Date::RSS)
+        );
+        $updated->appendChild($text);
     }
     
     /**
@@ -198,7 +196,8 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
             if (array_key_exists('email', $data)) {
                 $name = $data['email'] . ' (' . $data['name'] . ')';
             }
-            $author->nodeValue = $name;
+            $text = $dom->createTextNode($name);
+            $author->appendChild($text);
             $root->appendChild($author);
         }
     }
@@ -237,7 +236,8 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
         }
         $link = $dom->createElement('link');
         $root->appendChild($link);
-        $link->nodeValue = $this->getDataContainer()->getLink();
+        $text = $dom->createTextNode($this->getDataContainer()->getLink());
+        $link->appendChild($text);
     }
     
     /**
@@ -260,7 +260,8 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
             $this->getDataContainer()->setId(
                 $this->getDataContainer()->getLink());
         }
-        $id->nodeValue = $this->getDataContainer()->getId();
+        $text = $dom->createTextNode($this->getDataContainer()->getId());
+        $id->appendChild($text);
         if (!Zend_Uri::check($this->getDataContainer()->getId())) {
             $id->setAttribute('isPermaLink', 'false');
         }
@@ -280,7 +281,32 @@ class Zend_Feed_Writer_Renderer_Entry_Rss
             return;
         }
         $clink = $this->_dom->createElement('comments');
-        $clink->nodeValue = $link;
+        $text = $dom->createTextNode($link);
+        $clink->appendChild($text);
         $root->appendChild($clink);
     }
+    
+    /**
+     * Set entry categories
+     * 
+     * @param DOMDocument $dom 
+     * @param DOMElement $root 
+     * @return void
+     */
+    protected function _setCategories(DOMDocument $dom, DOMElement $root)
+    {
+        $categories = $this->getDataContainer()->getCategories();
+        if (!$categories) {
+            return;
+        }
+        foreach ($categories as $cat) {
+            $category = $dom->createElement('category');
+            if (isset($cat['scheme'])) {
+                $category->setAttribute('domain', $cat['scheme']);
+            }
+            $text = $dom->createCDATASection($cat['term']);
+            $category->appendChild($text);
+            $root->appendChild($category);
+        }
+    }
 }

+ 22 - 16
library/Zend/Feed/Writer/Renderer/Feed/Atom.php

@@ -152,7 +152,8 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
         $title = $dom->createElement('title');
         $root->appendChild($title);
         $title->setAttribute('type', 'text');
-        $title->nodeValue = $this->getDataContainer()->getTitle();
+        $text = $dom->createTextNode($this->getDataContainer()->getTitle());
+        $title->appendChild($text);
     }
 
     /**
@@ -170,7 +171,8 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
         $subtitle = $dom->createElement('subtitle');
         $root->appendChild($subtitle);
         $subtitle->setAttribute('type', 'text');
-        $subtitle->nodeValue = $this->getDataContainer()->getDescription();
+        $text = $dom->createTextNode($this->getDataContainer()->getDescription());
+        $subtitle->appendChild($text);
     }
 
     /**
@@ -197,8 +199,10 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
 
         $updated = $dom->createElement('updated');
         $root->appendChild($updated);
-        $updated->nodeValue = $this->getDataContainer()->getDateModified()
-            ->get(Zend_Date::ISO_8601);
+        $text = $dom->createTextNode(
+            $this->getDataContainer()->getDateModified()->get(Zend_Date::ISO_8601)
+        );
+        $updated->appendChild($text);
     }
 
     /**
@@ -218,7 +222,8 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
         $gdata = $this->getDataContainer()->getGenerator();
         $generator = $dom->createElement('generator');
         $root->appendChild($generator);
-        $generator->nodeValue = $gdata['name'];
+        $text = $dom->createTextNode($gdata['name']);
+        $generator->appendChild($text);
         if (array_key_exists('uri', $gdata)) {
             $generator->setAttribute('uri', $gdata['uri']);
         }
@@ -304,16 +309,19 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
             $name = $this->_dom->createElement('name');
             $author->appendChild($name);
             $root->appendChild($author);
-            $name->nodeValue = $data['name'];
+            $text = $dom->createTextNode($data['name']);
+            $name->appendChild($text);
             if (array_key_exists('email', $data)) {
                 $email = $this->_dom->createElement('email');
                 $author->appendChild($email);
-                $email->nodeValue = $data['email'];
+                $text = $dom->createTextNode($data['email']);
+                $email->appendChild($text);
             }
             if (array_key_exists('uri', $data)) {
                 $uri = $this->_dom->createElement('uri');
                 $author->appendChild($uri);
-                $uri->nodeValue = $data['uri'];
+                $text = $dom->createTextNode($data['uri']);
+                $uri->appendChild($text);
             }
         }
     }
@@ -349,7 +357,8 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
         }
         $id = $dom->createElement('id');
         $root->appendChild($id);
-        $id->nodeValue = $this->getDataContainer()->getId();
+        $text = $dom->createTextNode($this->getDataContainer()->getId());
+        $id->appendChild($text);
     }
     
     /**
@@ -367,7 +376,8 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
         }
         $copy = $dom->createElement('rights');
         $root->appendChild($copy);
-        $copy->nodeValue = $copyright;
+        $text = $dom->createTextNode($copyright);
+        $copy->appendChild($text);
     }
     
     /**
@@ -443,13 +453,9 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
             $category = $dom->createElement('category');
             $category->setAttribute('term', $cat['term']);
             if (isset($cat['label'])) {
-                $category->setAttribute('label',
-                    htmlentities($cat['label'], ENT_QUOTES, $this->getDataContainer()->getEncoding())
-                );
+                $category->setAttribute('label', $cat['label']);
             } else {
-                $category->setAttribute('label',
-                    htmlentities($cat['term'], ENT_QUOTES, $this->getDataContainer()->getEncoding())
-                );
+                $category->setAttribute('label', $cat['term']);
             }
             if (isset($cat['scheme'])) {
                 $category->setAttribute('scheme', $cat['scheme']);

+ 19 - 17
library/Zend/Feed/Writer/Renderer/Feed/Rss.php

@@ -67,6 +67,7 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
         }
         $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding());
         $this->_dom->formatOutput = true;
+        $this->_dom->substituteEntities = false;
         $rss = $this->_dom->createElement('rss');
         $this->setRootElement($rss);
         $rss->setAttribute('version', '2.0');
@@ -153,11 +154,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
 
         $title = $dom->createElement('title');
         $root->appendChild($title);
-        $title->nodeValue = htmlentities(
-            $this->getDataContainer()->getTitle(),
-            ENT_QUOTES,
-            $this->getDataContainer()->getEncoding()
-        );
+        $text = $dom->createTextNode($this->getDataContainer()->getTitle());
+        $title->appendChild($text);
     }
 
     /**
@@ -183,11 +181,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
         }
         $subtitle = $dom->createElement('description');
         $root->appendChild($subtitle);
-        $subtitle->nodeValue = htmlentities(
-            $this->getDataContainer()->getDescription(),
-            ENT_QUOTES,
-            $this->getDataContainer()->getEncoding()
-        );
+        $text = $dom->createTextNode($this->getDataContainer()->getDescription());
+        $subtitle->appendChild($text);
     }
 
     /**
@@ -205,8 +200,10 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
 
         $updated = $dom->createElement('pubDate');
         $root->appendChild($updated);
-        $updated->nodeValue = $this->getDataContainer()->getDateModified()
-            ->get(Zend_Date::RSS);
+        $text = $dom->createTextNode(
+            $this->getDataContainer()->getDateModified()->get(Zend_Date::RSS)
+        );
+        $updated->appendChild($text);
     }
 
     /**
@@ -233,7 +230,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
         if (array_key_exists('uri', $gdata)) {
             $name .= ' (' . $gdata['uri'] . ')';
         }
-        $generator->nodeValue = $name;
+        $text = $dom->createTextNode($name);
+        $generator->appendChild($text);
     }
 
     /**
@@ -260,7 +258,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
         }
         $link = $dom->createElement('link');
         $root->appendChild($link);
-        $link->nodeValue = $value;
+        $text = $dom->createTextNode($value);
+        $link->appendChild($text);
         if (!Zend_Uri::check($value)) {
             $link->setAttribute('isPermaLink', 'false');
         }
@@ -285,7 +284,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
             if (array_key_exists('email', $data)) {
                 $name = $data['email'] . ' (' . $data['name'] . ')';
             }
-            $author->nodeValue = $name;
+            $text = $dom->createTextNode($name);
+            $author->appendChild($text);
             $root->appendChild($author);
         }
     }
@@ -305,7 +305,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
         }
         $copy = $dom->createElement('copyright');
         $root->appendChild($copy);
-        $copy->nodeValue = $copyright;
+        $text = $dom->createTextNode($copyright);
+        $copy->appendChild($text);
     }
     
     /**
@@ -361,7 +362,8 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
             if (isset($cat['scheme'])) {
                 $category->setAttribute('domain', $cat['scheme']);
             }
-            $category->nodeValue = $cat['term'];
+            $text = $dom->createTextNode($cat['term']);
+            $category->appendChild($text);
             $root->appendChild($category);
         }
     }

+ 17 - 0
tests/Zend/Feed/Writer/Renderer/Entry/AtomTest.php

@@ -262,6 +262,23 @@ class Zend_Feed_Writer_Renderer_Entry_AtomTest extends PHPUnit_Framework_TestCas
         $this->assertEquals(22, $entry->getCommentCount());
     }
     
+    public function testCategoriesCanBeSet()
+    {
+        $this->_validEntry->addCategories(array(
+            array('term'=>'cat_dog', 'label' => 'Cats & Dogs', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2')
+        ));
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $entry = $feed->current();
+        $expected = array(
+            array('term'=>'cat_dog', 'label' => 'Cats & Dogs', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2', 'label' => 'cat_dog2', 'scheme' => null)
+        );
+        $this->assertEquals($expected, (array) $entry->getCategories());
+    }
+    
     public function testCommentFeedLinksRendered()
     {
         $renderer = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);

+ 75 - 3
tests/Zend/Feed/Writer/Renderer/Entry/RssTest.php

@@ -101,13 +101,22 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
     /**
      * @expectedException Zend_Feed_Exception
      */
-    public function testFeedTitleIfMissingThrowsExceptionIfDescriptionAlsoMissing()
+    public function testEntryTitleIfMissingThrowsExceptionIfDescriptionAlsoMissing()
     {
         $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
         $this->_validEntry->remove('title');
         $this->_validEntry->remove('description');
         $atomFeed->render();
     }
+    
+    public function testEntryTitleCharDataEncoding()
+    {
+        $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $this->_validEntry->setTitle('<>&\'"áéíóú');
+        $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
+        $entry = $feed->current();
+        $this->assertEquals('<>&\'"áéíóú', $entry->getTitle());
+    }
 
     public function testEntrySummaryDescriptionHasBeenSet()
     {
@@ -120,7 +129,7 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
     /**
      * @expectedException Zend_Feed_Exception
      */
-    public function testFeedDescriptionIfMissingThrowsExceptionIfAlsoNoTitle()
+    public function testEntryDescriptionIfMissingThrowsExceptionIfAlsoNoTitle()
     {
         $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
         $this->_validEntry->remove('description');
@@ -128,6 +137,15 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
         $atomFeed->render();
     }
     
+    public function testEntryDescriptionCharDataEncoding()
+    {
+        $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $this->_validEntry->setDescription('<>&\'"áéíóú');
+        $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
+        $entry = $feed->current();
+        $this->assertEquals('<>&\'"áéíóú', $entry->getDescription());
+    }
+    
     public function testEntryContentHasBeenSet()
     {
         $this->_validEntry->setContent('This is test entry content.');
@@ -136,6 +154,15 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
         $entry = $feed->current();
         $this->assertEquals('This is test entry content.', $entry->getContent());
     }
+    
+    public function testEntryContentCharDataEncoding()
+    {
+        $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $this->_validEntry->setContent('<>&\'"áéíóú');
+        $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
+        $entry = $feed->current();
+        $this->assertEquals('<>&\'"áéíóú', $entry->getContent());
+    }
 
     public function testEntryUpdatedDateHasBeenSet()
     {
@@ -173,6 +200,16 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
         $this->assertEquals(array('name'=>'Jane'), $entry->getAuthor());
     }
     
+    public function testEntryAuthorCharDataEncoding()
+    {
+        $this->_validEntry->addAuthor('<>&\'"áéíóú', 'jane@example.com', 'http://www.example.com/jane');
+        $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
+        $entry = $feed->current();
+        $author = $entry->getAuthor();
+        $this->assertEquals(array('name'=>'<>&\'"áéíóú'), $entry->getAuthor());
+    }
+    
     public function testEntryHoldsAnyEnclosureAdded()
     {
         $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
@@ -203,7 +240,7 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
         $this->markTestIncomplete('Untest due to ZFR potential bug');
     }
 
-    public function testFeedIdDefaultIsUsedIfNotSetByHand()
+    public function testEntryIdDefaultIsUsedIfNotSetByHand()
     {
         $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
         $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
@@ -242,5 +279,40 @@ class Zend_Feed_Writer_Renderer_Entry_RssTest extends PHPUnit_Framework_TestCase
         $this->assertEquals('http://www.example.com/rss/id/1', $entry->getCommentFeedLink('rss'));
         //$this->assertEquals('http://www.example.com/atom/id/1', $entry->getCommentFeedLink('atom'));
     }
+    
+    public function testCategoriesCanBeSet()
+    {
+        $this->_validEntry->addCategories(array(
+            array('term'=>'cat_dog', 'label' => 'Cats & Dogs', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2')
+        ));
+        $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
+        $entry = $feed->current();
+        $expected = array(
+            array('term'=>'cat_dog', 'label' => 'cat_dog', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2', 'label' => 'cat_dog2', 'scheme' => null)
+        );
+        $this->assertEquals($expected, (array) $entry->getCategories());
+    }
+    
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testCategoriesCharDataEncoding()
+    {
+        $this->_validEntry->addCategories(array(
+            array('term'=>'<>&\'"áéíóú', 'label' => 'Cats & Dogs', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2')
+        ));
+        $renderer = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $feed = Zend_Feed_Reader::importString($renderer->render()->saveXml());
+        $entry = $feed->current();
+        $expected = array(
+            array('term'=>'<>&\'"áéíóú', 'label' => '<>&\'"áéíóú', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2', 'label' => 'cat_dog2', 'scheme' => null)
+        );
+        $this->assertEquals($expected, (array) $entry->getCategories());
+    }
 
 }

+ 81 - 3
tests/Zend/Feed/Writer/Renderer/Feed/AtomTest.php

@@ -109,6 +109,18 @@ class Zend_Feed_Writer_Renderer_Feed_AtomTest extends PHPUnit_Framework_TestCase
         $this->_validWriter->remove('title');
         $atomFeed->render();
     }
+    
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedTitleCharDataEncoding()
+    {
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $this->_validWriter->setTitle('<>&\'"áéíóú');
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getTitle());
+    }
 
     public function testFeedSubtitleHasBeenSet()
     {
@@ -124,6 +136,18 @@ class Zend_Feed_Writer_Renderer_Feed_AtomTest extends PHPUnit_Framework_TestCase
         $this->_validWriter->remove('description');
         $atomFeed->render();
     }
+    
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedSubtitleCharDataEncoding()
+    {
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $this->_validWriter->setDescription('<>&\'"áéíóú');
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getDescription());
+    }
 
     public function testFeedUpdatedDateHasBeenSet()
     {
@@ -166,6 +190,18 @@ class Zend_Feed_Writer_Renderer_Feed_AtomTest extends PHPUnit_Framework_TestCase
         $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
         $this->assertEquals('Zend_Feed_Writer', $feed->getGenerator());
     }
+    
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedGeneratorCharDataEncoding()
+    {
+        $this->_validWriter->setGenerator('<>&\'"áéíóú', '1.00', 'http://www.example.com');
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getGenerator());
+    }
 
     public function testFeedLanguageHasBeenSet()
     {
@@ -247,6 +283,26 @@ class Zend_Feed_Writer_Renderer_Feed_AtomTest extends PHPUnit_Framework_TestCase
             'uri'=>'http://www.example.com/joe'), $feed->getAuthor());
     }
     
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedAuthorCharDataEncoding()
+    {
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $this->_validWriter->remove('authors');
+        $this->_validWriter->addAuthor(array(
+            'email'=>'<>&\'"áéíóú',
+            'name'=>'<>&\'"áéíóú',
+            'uri'=>'http://www.example.com/joe'));
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $author = $feed->getAuthor();
+        $this->assertEquals(array(
+            'email'=>'<>&\'"áéíóú',
+            'name'=>'<>&\'"áéíóú',
+            'uri'=>'http://www.example.com/joe'), $feed->getAuthor());
+    }
+    
     public function testFeedAuthorIfNotSetThrowsExceptionIfAnyEntriesAlsoAreMissingAuthors()
     {
         $this->markTestIncomplete('Not yet implemented...');
@@ -292,6 +348,15 @@ class Zend_Feed_Writer_Renderer_Feed_AtomTest extends PHPUnit_Framework_TestCase
         $this->assertEquals('Copyright © 2009 Paddy', $feed->getCopyright());
     }
     
+    public function testCopyrightCharDataEncoding()
+    {
+        $this->_validWriter->setCopyright('<>&\'"áéíóú');
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getCopyright());
+    }
+    
     public function testCategoriesCanBeSet()
     {
         $this->_validWriter->addCategories(array(
@@ -308,9 +373,22 @@ class Zend_Feed_Writer_Renderer_Feed_AtomTest extends PHPUnit_Framework_TestCase
         $this->assertEquals($expected, (array) $feed->getCategories());
     }
     
-    /**
-     * @group ZFW030
-     */
+    public function testCategoriesCharDataEncoding()
+    {
+        $this->_validWriter->addCategories(array(
+            array('term'=>'cat_dog', 'label' => '<>&\'"áéíóú', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2')
+        ));
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Atom($this->_validWriter);
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $expected = array(
+            array('term'=>'cat_dog', 'label' => '<>&\'"áéíóú', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2', 'label' => 'cat_dog2', 'scheme' => null)
+        );
+        $this->assertEquals($expected, (array) $feed->getCategories());
+    }
+    
     public function testHubsCanBeSet()
     {
         $this->_validWriter->addHubs(

+ 68 - 0
tests/Zend/Feed/Writer/Renderer/Feed/RssTest.php

@@ -107,6 +107,18 @@ class Zend_Feed_Writer_Renderer_Feed_RssTest extends PHPUnit_Framework_TestCase
         $rssFeed->render();
     }
 
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedTitleCharDataEncoding()
+    {
+        $rssFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $this->_validWriter->setTitle('<>&\'"áéíóú');
+        $rssFeed->render();
+        $feed = Zend_Feed_Reader::importString($rssFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getTitle());
+    }
+
     public function testFeedDescriptionHasBeenSet()
     {
         $rssFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
@@ -124,6 +136,18 @@ class Zend_Feed_Writer_Renderer_Feed_RssTest extends PHPUnit_Framework_TestCase
         $this->_validWriter->remove('description');
         $rssFeed->render();
     }
+    
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedDescriptionCharDataEncoding()
+    {
+        $rssFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $this->_validWriter->setDescription('<>&\'"áéíóú');
+        $rssFeed->render();
+        $feed = Zend_Feed_Reader::importString($rssFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getDescription());
+    }
 
     public function testFeedUpdatedDateHasBeenSet()
     {
@@ -245,6 +269,19 @@ class Zend_Feed_Writer_Renderer_Feed_RssTest extends PHPUnit_Framework_TestCase
         $this->assertEquals(array('name'=>'Joe'), $feed->getAuthor());
     }
     
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testFeedAuthorCharDataEncoding()
+    {   
+        $this->_validWriter->addAuthor('<>&\'"áéíóú', 'joe@example.com', 'http://www.example.com/joe');
+        $atomFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $atomFeed->render();
+        $feed = Zend_Feed_Reader::importString($atomFeed->saveXml());
+        $author = $feed->getAuthor();
+        $this->assertEquals(array('name'=>'<>&\'"áéíóú'), $feed->getAuthor());
+    }
+    
     public function testCopyrightCanBeSet()
     {
         $this->_validWriter->setCopyright('Copyright © 2009 Paddy');
@@ -254,6 +291,18 @@ class Zend_Feed_Writer_Renderer_Feed_RssTest extends PHPUnit_Framework_TestCase
         $this->assertEquals('Copyright © 2009 Paddy', $feed->getCopyright());
     }
     
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testCopyrightCharDataEncoding()
+    {
+        $this->_validWriter->setCopyright('<>&\'"áéíóú');
+        $rssFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $rssFeed->render();
+        $feed = Zend_Feed_Reader::importString($rssFeed->saveXml());
+        $this->assertEquals('<>&\'"áéíóú', $feed->getCopyright());
+    }
+    
     public function testCategoriesCanBeSet()
     {
         $this->_validWriter->addCategories(array(
@@ -270,6 +319,25 @@ class Zend_Feed_Writer_Renderer_Feed_RssTest extends PHPUnit_Framework_TestCase
         $this->assertEquals($expected, (array) $feed->getCategories());
     }
     
+    /**
+     * @group ZFWCHARDATA01
+     */
+    public function testCategoriesCharDataEncoding()
+    {
+        $this->_validWriter->addCategories(array(
+            array('term'=>'<>&\'"áéíóú', 'label' => 'Cats & Dogs', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2')
+        ));
+        $rssFeed = new Zend_Feed_Writer_Renderer_Feed_Rss($this->_validWriter);
+        $rssFeed->render();
+        $feed = Zend_Feed_Reader::importString($rssFeed->saveXml());
+        $expected = array(
+            array('term'=>'<>&\'"áéíóú', 'label' => '<>&\'"áéíóú', 'scheme' => 'http://example.com/schema1'),
+            array('term'=>'cat_dog2', 'label' => 'cat_dog2', 'scheme' => null)
+        );
+        $this->assertEquals($expected, (array) $feed->getCategories());
+    }
+    
     public function testHubsCanBeSet()
     {
         $this->_validWriter->addHubs(