dapepe / xily
Xily是一个轻量级的PHP框架,用于开发基于XML的应用程序。
Requires
- php: >=5.4.0
This package is not auto-updated.
Last update: 2024-09-18 19:09:07 UTC
README
目的
Xily是一个轻量级的PHP框架,用于开发基于XML的应用程序。该框架包含五个核心类,使工作变得可能。一个主要方面是使用类似DOM的对象模型表示XML数据。基于此模型,您可以使用Xily为每个XML标签添加单个解析器(xilyBeans),从而使开发人员能够创建模块化、XML驱动的Web应用程序。
一点历史
Xily是由Peter Haider在ZeyOS(http://www.zeyos.com)开发的。开发始于2008年,当时团队需要一个框架来开发网站和门户。当时我们正在查看许多基于XML的模板系统,如Adobe ColdFusion、Open Laszlo或Adobe Flex。使用XML描述前端部分的方法真的吸引了我们,我们认为我们可能希望为PHP拥有类似的东西。而且,由于每个项目可能都有不同的要求,因此将XML引擎扩展为新行为和标签会很好。
所有这些的结果是Xily,一个框架,使我们能够(a。)在PHP中处理XML文档,并且(b。)通过简单地封装称为Xily Beans的复杂对象和程序逻辑来开发完全基于XML的应用程序和网站。
为什么选择Xily?
轻量级
Xily专注于其核心功能——即利用XML。核心库总共由5个文件组成!
专注
Xily只有一个目的:在PHP中创建XML驱动的应用程序。您可以使用xilyXML库简单地处理XML文档,而xilyBeans则允许您通过开发自己的XML命令集来创建XML驱动的应用程序和网站。
可扩展
您可以随着项目的发展扩展和增强Xily。Xily不会强迫您采用任何特定的方法——您甚至可以创建自己的XML命令集。
主要组件
Xily XML
使用XML
类处理XML结构。它可以用来解析XML文件/字符串,或动态地处理这些信息,或操纵XML结构。
Xily Bean
Bean
类允许您将应用程序逻辑附加到特定的XML标签上,这意味着您可以实际定义自己的自定义XML命令面板。
Xily Dictionary
Dictionary
类提供XML和Array之间的接口,以便在Bean
类中将数组视为XML树。
Xily Config
Config
类是一个Singleton
,提供对全局配置设置的访问。
Xily Base
Base
类提供由Dict
、XML
和Bean
类共享的基本实用方法。
测试和示例
Xily XML
您将在/test
目录中找到一些测试用例。让我们看看如何处理XML文件的一个快速示例。
<?xml version="1.0" encoding="UTF-8"?> <recipes> <recipe level="easy" cookingtime="10"> <title>Pancakes</title> <ingredients> <item>200g flour</item> <item>2 eggs</item> <item>3 tea spoons of sugar</item> <item>100ml milk</item> <item>100ml water</item> </ingredients> </recipe> <recipe level="medium" cookingtime="20"> <title>Barbecue steak</title> <ingredients> <item>250g steak</item> <item>5 potatoes</item> <item>Oil</item> <item>Pepper</item> <item>Salt</item> <item>Garlic</item> <item>Chilli</item> </ingredients> </recipe> <recipe level="easy" cookingtime="5"> <title>Scrambled eggs</title> <ingredients> <item>3 eggs</item> <item>Pepper</item> <item>Salt</item> </ingredients> </recipe> </recipes>
首先,我们将从文件中加载XML结构。
$xmlRecipes = Xily\XML::create('data/recipes.xml', true);
Xily XML使用类似于E4X的语法来选择结构中的节点。getNodeByPath
函数获取所有与路径描述匹配的节点。此示例列出所有烹饪时间低于20分钟的食谱。
$arrRecipes = $xmlRecipes->getNodesByPath('recipe(@cookingtime < 30)'); foreach ($arrRecipes as $xmlRecipe) echo $xmlRecipe->trace('title');
如果您只想选择单个节点,可以使用getNodeByPath函数。这将选择烹饪时间低于30分钟且易于准备的第一个节点。
$xmlSomeRecipe = $xmlRecipes->getNodeByPath('recipe(@cookingtime < 30, @level == "easy")');
跟踪返回所需节点的值或属性,而不是节点本身。以下示例获取“title”节点的值。
$xmlRecipes->trace('recipe(@id == "soup").title');
这相当于
$xmlRecipes->getNodeByPath('recipe(@id == "soup")')->child('title')->value();
您还可以使用子路径作为选择器。让我们获取所有包含“盐”作为成分的食谱
$arrRecipes = $xmlRecipes->getNodesByPath('recipe(ingredients.item == "Salt")');
更多示例,请查看示例脚本 test/test.xml.php
Xily Bean
在开发基于XML的应用程序时,您不仅想使用XML来定义应用程序的结构和数据,还想定义其行为和表示。Xily Beans允许您将应用程序分解为单个、可重用的单元,并通过在XML结构中代表它们来访问这些单元。这样,您就可以直接在XML中开发应用程序,就像在Adobe Flex或OpenLaszlo中一样,因为实际的编码功能嵌入在您的Xily Bean类中。这样,您可以专注于诸如设计、架构和可用性等因素,而不是编码过程本身。
创建自定义Beans
让我们创建一个简单的示例。假设我们想创建一个简单的HTML表单。对于此示例,我们将使用Bootstrap CSS 3.0.2
这就是该表单在常规HTML中的样子
<form class="form-horizontal" role="form"> <div class="form-group"> <label for="txtFirstname" class="col-sm-2 control-label">First name <span class="glyphicon glyphicon-asterisk"></span></label> <div class="col-sm-10"> <input type="text" class="form-control" name="txtFirstname"> </div> </div> <div class="form-group"> <label for="txtLastname" class="col-sm-2 control-label">Last name <span class="glyphicon glyphicon-asterisk"></span></label> <div class="col-sm-10"> <input type="text" class="form-control" name="txtLastname"> </div> </div> <div class="form-group"> <label for="txtEmail" class="col-sm-2 control-label">E-mail</label> <div class="col-sm-10"> <input type="email" class="form-control" name="txtEmail"> </div> </div> <div class="form-group"> <label for="txtRegion" class="col-sm-2 control-label">Region</label> <div class="col-sm-10"> <select class="form-control" id="txtRegion" name="region"> <option value="">- Please Select -</option> <option value="North America">North America</option> <option value="Central America">Central America</option> <option value="South America">South America</option> <option value="European Union">European Union</option> <option value="Eastern Europe">Eastern Europe</option> <option value="Africa">Africa</option> <option value="Middle East">Middle East</option> <option value="Asia">Asia</option> <option value="Oceania">Oceania</option> <option value="The Caribbean">The Caribbean</option> </select> </div> </div> </form>
如您所见,有很多重复的HTML可以被轻松避免。此外,如果您想稍后更新Bootstrap,类名和HTML结构可能会发生变化怎么办?出于这个原因,创建一个用于表单元素的类更为高效。
写这样的东西不是更好吗?
<form:frame width="2"> <form:field name="Firstname" label="First name" required="true" /> <form:field name="Lastname" label="Last name" required="true" /> <form:field name="Email" label="E-mail" type="email" /> <form:field name="region" label="Region?" placeholder="- Please Select -"> <option>North America</option> <option>Central America</option> <option>South America</option> <option>European Union</option> <option>Eastern Europe</option> <option>Africa</option> <option>Middle East</option> <option>Asia</option> <option>Oceania</option> <option>The Caribbean</option> </form:field> </form:frame>
更少杂乱,对吧?为了实现这一点,我们只需向我们的项目中添加两个新的Bean类
class FormFrame extends Bean { public function result($xmlData, $intLevel=0) { if ($this->hasAttribute('left')) { if ($xmlData instanceof XML) $xmlData->setAttribute('left', $this->attribute('left')); else $xmlData = new XML('data', null, array('left' => $this->attribute('left'))); } return '<form class="form-horizontal" role="form"' .($this->hasAttribute('id') ? ' id="'.$this->attribute('id').'"' : '') .($this->hasAttribute('action') ? ' action="'.$this->attribute('action').'"' : '') .($this->hasAttribute('target') ? ' target="'.$this->attribute('target').'"' : '') .($this->hasAttribute('style') ? ' style="'.$this->attribute('style').'"' : '') .'>' .$this->dump($xmlData, $intLevel+1) .'</form>'; } } class FormField extends Bean { public function result($xmlData, $intLevel=0) { $widthLeft = 2; if ($this->hasAttribute('left')) $widthLeft = (int) $this->attribute('left'); elseif ($xmlData instanceof XML && $xmlData->hasAttribute('left')) $widthLeft = (int) $xmlData->attribute('left'); $widthRight = 12 - $widthLeft; // Bootstrap's grid system is based on 12 columns $id = $this->attribute('id'); $name = $this->attribute('name'); if (!$id || $id == '') { if (!$name || $name == '') return; // Either a name or an ID will have to be specified $id = 'txt'.ucfirst($name); // Automatically create an ID based on the name } elseif (!$name || $name == '') { $name = $id; } $elem = '<div class="form-group">' .'<label for="'.$id.'" class="col-sm-'.$widthLeft.' control-label">' .$this->attribute('label') .($this->isTrue('required') ? '<span class="glyphicon glyphicon-asterisk" />' : '') .'</label>' .'<div class="col-sm-'.$widthRight.'">'; if ($this->hasChildren()) { $elem .= '<select class="form-control" id="'.$id.'" name="'.$name.'">' .($this->hasAttribute('placeholder') ? '<option value="">'.$this->attribute('placeholder').'</option>' : ''); foreach ($this->children() as $xmlChild) { if (!$xmlChild->hasAttribute('value')) $xmlChild->setAttribute('value', trim($xmlChild->value())); if ($this->hasAttribute('selected') && $this->attribute('selected') == $xmlChild->attribute('value')) $xmlChild->setAttribute('selected', 'selected'); $elem .= $xmlChild->toString(); } $elem .= '</select>'; } elseif ($this->attribute('type') == 'multi') { $elem .= '<textarea class="form-control" name="'.$id.'" name="'.$name.'" rows="'.($this->hasAttribute('rows') ? $this->attribute('rows') : 3).'"></textarea>'; } else { $elem .= '<input type="'.($this->hasAttribute('type') ? $this->attribute('type') : 'text').'"' .($this->hasAttribute('placeholder') ? ' placeholder="'.$this->attribute('placeholder').'"' : '') .' class="form-control" name="'.$id.'" name="'.$name.'" />'; } return $elem.'</div></div>'; } }
这两个类自动生成整个表单。现在您有了可重用组件类,您可以像HTML标签一样对待它们。
为了使您更容易与不同的Bean库一起工作,Xily在解析XML文件时使用懒加载来包含所需的文件。您只需通过将它们添加到Bean
类的BEAN_DIRS
数组中,就可以包含您的bean目录。
\Xily\Bean::$BEAN_DIRS[] = LIB_DIR.'xily/src/beans'; \Xily\Bean::$BEAN_DIRS[] = LIB_DIR.'custombeans';
继续我们之前的例子:对于我们的自定义Beans <form:frame/>
和 <form:field/>
,我们在custombeans
目录中创建一个名为form
的目录,并创建两个名为frame.php
和field.php
的文件,每个文件都包含相应的Bean类。
使用Xily数据引用(XDR)
除了定义自定义Beans之外,Xily数据引用(XDR)也是Xily的一个重要方面。XDRs允许您动态地引用和访问文档中的数据。
让我们有一个简单的例子:您想创建一个小型门户页面,其中还想要显示您的博客的最新帖子,并在列表中优雅地显示它们。
<html> <repeat source="#{.get(http://feeds.bbci.co.uk/news/technology/rss.xml)->xml->channel.item}"> <div> <h3>#{title}</h3> <p>#{description}</p> <a href="#{link}">Read all</a> </div> </repeat> </html>
XDRs提供了多种方法来动态访问数据。有7种不同的XDR类型,以提供广泛的访问可能性
您还可以访问PHP的预定义变量
Xily Config
可以使用Config
类来加载和访问全局应用程序配置设置。
您可以从JSON或INI文件加载配置设置,例如
Xily\Config::load('config.ini');
但是,您也可以使用load
方法直接加载关联数组
Xily\Config::load([ 'general' => [ 'option1' => 'value1', 'option2' => 'value2' ] ]);
您可以使用get
方法访问配置选项。当加载多维配置文件时,您可以使用简单的点连接选择单个节点,例如
Xily\Config::get('general.option1'); // Return "value1"
同样,您可以使用set
方法更改或设置单个配置值,例如
Xily\Config::set('general.option1', 'new value');
《Config》类还包括初始化返回值的方法。例如,如果您的配置文件包含对目录的引用,您可能希望确保值在目录名称的末尾有一个尾随的反斜杠
Xily\Config::set('mydir', '/var/www'); Xily\Config::getDir('mydir'); // Return "/var/www/"
此外,您还可以使用 get
方法将特定变量类型进行类型转换,以及初始化默认值。
; config.ini
[general]
dir = "/var/www"
debug = 0
[numeric]
taxrate = "1,20"
discount = "0.60"
在 get
方法的附加参数中指定期望的变量类型(字符串、整数、浮点数、数组、布尔值、对象)和默认值
Xily\Config::load('config.ini'); Xily\Config::get('general.debug', 'bool', true); // Returns FALSE Xily\Config::get('numeric.taxrate', 'float', 1.19); // Returns the default value 1.19 Xily\Config::get('numeric.discount', 'float', 0); // Return 0.6
更多示例,请查看示例脚本 test/test.config.php
贡献
目前,Xily 被许多不同的项目使用,因此我一直在努力改进和测试该框架。我从 2008 年开始开发 Xily,所以到目前为止,整体结构和功能已经得到了很好的测试。然而,我很乐意找到更多项目参与者。我特别希望得到以下方面的帮助:
- 调试和测试
- 添加更多示例和教程
- 维护 Xily 网站
- 编写新的 Xily Beans 以扩展整体功能
如果您有兴趣——我期待着您的消息!只需在 GitHub 上给我发消息。
许可协议
版权(C)2008-2016 彼得-克里斯托夫·海德尔
本作品受 GNU 较小通用公共许可证(LGPL)的许可,应随此软件一同提供。您也可以从 https://gnu.ac.cn/licenses/lgpl.txt 获取 GNU 较小通用公共许可证的副本。