# -*- coding: utf-8 -*- # # This file is a part of Fedora-tour http://fedoraproject.org/wiki/Fedora-tour # # Copyright (c) 2009 Ryan Rix # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # import io import os.path import xml.parsers.expat import sys """ This will be expanded as more is added to the nodes. """ class MenuNode: parent = False nodes = list() nodeType = False def __init__(self, nodeType): self.nodeType = nodeType """ Each one of these objects represents one section of Fedora-tour and all of the content which exists below it. The frontend should keep these in a list, ordered by MenuObject.Priority What this sort of does is create a lazy DOM of menuNode objects where each menuNode has a list of children and a single parent, linked directly to the object, to create a virtual layout of the XML. node.nodeType = package nodes: page 1 nodes: page 2 parent: 0 node.nodeType = Page parent: Package content and stuff node.nodeType = Page parent: Package content and stuff """ class MenuObject: isValid = True currenElement = "powo" rootNode = False activeNode = False """ These Objects are representations of the and tags. """ Icon = False IconID = False DocRoot = False Locale = False Priority = False def __init__(self,package): """ Check if the file exists. When calling the constructor from the front end, the absolute path will have to be passed as an argument; this should probably change in the future. TODO: add code to support automatic generation of absolute URL when front end passes a package name """ if not os.path.isfile(package): self.isValid = False return None """ Create a parser as outlined at http://docs.python.org/library/pyexpat.html Basically, the parse has three functions in which it uses, CharacterDataHandler, StartElementHandler, and EndElementHandler. These functions take, for example, "", "fedora-logo-sprite", and "" respectively as arguments and these are used to create the object. """ print "Initializing and starting XML Parser for "+package+"." self.parser = xml.parsers.expat.ParserCreate() self.parser.CharacterDataHandler = self.parserCharData self.parser.StartElementHandler = self.parserStartElement self.parser.EndElementHandler = self.parserEndElement self.parser.ParseFile(open(package,"r")) """ The contents of IconID specify only the short name of an icon, not the full path; this function finds the full path of an icon and stores it in self.Icon """ self.Icon = self.makeIcon(self.IconID) def addNode(self,parent,nodeType): node = MenuNode(nodeType) if parent != False: node.parent = parent parent.nodes.append(node) return node """ This function parses the opening tags in the XML file and sets the proper value in self.currentElement for the parserCharData method to handle properly. This will probably a little bit more intuitively in the future, but for now it works. """ def parserStartElement(self, name, attrs): print "Encountered "+name+" node Start" self.currentElement = name if name == "Package": """ This is always assumed to be the root node. """ self.rootNode = self.addNode(False,"Package") self.activeNode = self.rootNode elif name == "Page": """ The Page entities are new nodes """ self.activeNode = self.addNode(self.activeNode, "Page") elif name == "Icon" or name == "DocRoot" or name == "Locale" or name == "Priority": """ These tags are only allowed under root, so we should err if this happens. """ if self.activeNode.parent != False: print "<"+name+"> node is only allowed underneath the Node. Please file a bug on the Fedora-tour Fedora component at http://bugzilla.redhat.com" sys.exit() """ I'm about 99% sure that this code could be written in a cleaner fashion and not so damn ugly, but here it is, assigning variables in the object. At some point, I'll look at moving these to attrs of the Page and Package entities, just so that the code could be a little bit cleaner. I know for sure that DisplayName could be in both and that Icon, DocRoot, Locale, and Priority could easily end up under Package. TODO: Rewrite this to be cleaner. TODO: Finish handlers for other entities, you missed a few. """ def parserCharData(self, data): if data == "": return if self.currentElement == "DisplayName": self.activeNode.displayName = data elif self.currentElement == "Icon": self.IconID = data elif self.currentElement == "DocRoot": self.DocRoot = data elif self.currentElement == "Locale": self.Locale = data elif self.currentElement == "Priority": self.Priority = data """ This just checks if a Page element is closing, since that will step us down one level in the "DOM" tree """ def parserEndElement(self, name): print "Encountered "+name+" node End" self.currentElement = "" if name == "Page": self.activeNode = self.activeNode.parent """ TODO """ def makeIcon(self, iconID): pass