Skip to content

Commit

Permalink
Fixed issue 333: XML Tree doesn't load if some item contains
Browse files Browse the repository at this point in the history
non-ASCII characters.
  • Loading branch information
Dmitry Vasiliev committed May 5, 2005
1 parent 6116809 commit bee3116
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 5 deletions.
1 change: 1 addition & 0 deletions tests/output/test1.xml
@@ -0,0 +1 @@
<?xml version="1.0" ?><children><collection name="" length="3" icon_url="" isroot=""><collection name="folder1" length="2" icon_url=""></collection><collection name="folder2" length="1" icon_url=""/><collection name="папка3" length="1" icon_url=""/><collection name="++etc++site" length="1" icon_url=""/></collection></children>
1 change: 1 addition & 0 deletions tests/output/test4.xml
@@ -0,0 +1 @@
<?xml version="1.0" ?><children><collection name="folder1" length="2" icon_url=""/><collection name="folder2" length="1" icon_url=""/><collection name="папка3" length="1" icon_url=""/><collection name="++etc++site" length="1" icon_url=""/></children>
1 change: 1 addition & 0 deletions tests/output/test5.xml
@@ -0,0 +1 @@
<?xml version="1.0" ?><children><collection name="" length="3" icon_url="" isroot=""><collection name="folder1" length="2" icon_url=""><collection name="folder1_1" length="2" icon_url=""><collection name="folder1_1_1" length="1" icon_url=""></collection><collection name="folder1_1_2" length="0" icon_url=""/><item name="++etc++site" /></collection><collection name="folder1_2" length="1" icon_url=""/><item name="++etc++site" /></collection><collection name="folder2" length="1" icon_url=""/><collection name="папка3" length="1" icon_url=""/><collection name="++etc++site" length="1" icon_url=""/></collection></children>
6 changes: 3 additions & 3 deletions tests/test_xmlnavigationviews.py
Expand Up @@ -36,7 +36,7 @@ class File(object):
pass

class TestXmlObject(PlacefulSetup, TestCase):

def setUp(self):
PlacefulSetup.setUp(self, site=True)
self.createStandardServices()
Expand All @@ -51,7 +51,7 @@ def testXMLTreeViews(self):

treeView = rcxov(self.folder1_1_1, TestRequest()).children
check_xml(treeView(), util.read_output('test3.xml'))

treeView = rcxov(self.rootFolder, TestRequest()).children
check_xml(treeView(), util.read_output('test4.xml'))

Expand All @@ -68,7 +68,7 @@ def publishTraverse(self, request, name):
raise NotFoundError(self, name, request)
def __call__(self):
return self.singleBranchTree()

ztapi.browserView(IReadContainer, 'singleBranchTree.xml',
ReadContainerView)

Expand Down
4 changes: 2 additions & 2 deletions tests/util.py
Expand Up @@ -24,8 +24,8 @@

def read_input(filename):
filename = os.path.join(input_dir, filename)
return open(filename, 'r').read()
return open(filename, 'r').read().decode("utf-8")

def read_output(filename):
filename = os.path.join(output_dir, filename)
return open(filename, 'r').read()
return open(filename, 'r').read().decode("utf-8")
164 changes: 164 additions & 0 deletions xmlobject.py
@@ -0,0 +1,164 @@
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Service manager interfaces
$Id$
"""

from zope.app.publisher.browser import BrowserView
from zope.app import zapi
from zope.app.container.interfaces import IReadContainer
from zope.app.traversing.api import getParents, getParent, traverse
from zope.interface import Interface
from rfc822 import formatdate, time
from xml.sax.saxutils import quoteattr

def setNoCacheHeaders(response):
"""Ensure that the tree isn't cached"""
response.setHeader('Pragma', 'no-cache')
response.setHeader('Cache-Control', 'no-cache')
response.setHeader('Expires', formatdate(time.time()-7*86400))#7 days ago

def xmlEscape(format, *args):
quotedArgs = [quoteattr(unicode(arg)) for arg in args]
return format % tuple(quotedArgs)

def xmlEscapeWithCData(format, *args):
cData = args[-1]
quotedArgs = [quoteattr(unicode(arg)) for arg in args[:-1]]
quotedArgsWithCData = quotedArgs + [cData]
return format % tuple(quotedArgsWithCData)


class ReadContainerXmlObjectView(BrowserView):
"""Provide a xml interface for dynamic navigation tree in UI"""

__used_for__ = IReadContainer


def getIconUrl(self, item):
result = ''
icon = zapi.queryView(item, 'zmi_icon', self.request)
if icon:
result = icon.url()
return result

def children_utility(self, container):
"""Return an XML document that contains the children of an object."""
result = []

keys = list(container.keys())

# include the service manager
keys.append(u'++etc++site')

for name in keys:

# Only include items we can traverse to
item = traverse(container, name, None)
if item is None:
continue

iconUrl = self.getIconUrl(item)
if IReadContainer.providedBy(item):
result.append(xmlEscape(
u'<collection name=%s length=%s icon_url=%s/>',
name, len(item), iconUrl))
else:
result.append(xmlEscape(
u'<item name=%s icon_url=%s/>',
name, iconUrl))

return u' '.join(result)


def children(self):
""" """
container = self.context
self.request.response.setHeader('Content-Type', 'text/xml')
setNoCacheHeaders(self.request.response)
res = (u'<?xml version="1.0" ?><children> %s </children>'
% self.children_utility(container))
return res

def singleBranchTree(self, root=''):
"""Return an XML document with the siblings and parents of an object.
There is only one branch expanded, in other words, the tree is
filled with the object, its siblings and its parents with
their respective siblings.
"""
result = ''
oldItem = self.context
for item in getParents(self.context):
# skip skin if present
#if item == oldItem:
# continue
subItems = []
if IReadContainer.providedBy(item):
keys = list(item.keys())
else:
keys = []

# include the service manager
keys.append(u'++etc++site')

for name in keys:
# Only include items we can traverse to
subItem = traverse(item, name, None)
if IReadContainer.providedBy(subItem):
iconUrl = self.getIconUrl(subItem)
# the test below seems to be browken with the ++etc++site case
if subItem == oldItem:
subItems.append(xmlEscapeWithCData(
u'<collection name=%s length=%s '
u'icon_url=%s>%s</collection>',
name, len(subItem), iconUrl, result))
else:
subItems.append(xmlEscape(
u'<collection name=%s length=%s '
u'icon_url=%s/>',
name, len(subItem), iconUrl))
else:
subItems.append(xmlEscape(u'<item name=%s />', name))

result = ' '.join(subItems)
oldItem = item

# do not forget root folder
iconUrl = self.getIconUrl(oldItem)
result = (xmlEscapeWithCData(u'<collection name="" length=%s '
u'icon_url=%s isroot="">%s</collection>',
len(oldItem), iconUrl, result))

self.request.response.setHeader('Content-Type', 'text/xml')
setNoCacheHeaders(self.request.response)
return u'<?xml version="1.0" ?><children> %s </children>' % result

class XmlObjectView(BrowserView):
"""Provide a xml interface for dynamic navigation tree in UI"""

__used_for__ = Interface

def singleBranchTree(self, root=''):
parent = getParent(self.context)
while parent is not None:
if IReadContainer.providedBy(parent):
view = zapi.queryView(parent,
'singleBranchTree.xml',
self.request)
return view()
else:
parent = getParent(parent)

0 comments on commit bee3116

Please sign in to comment.