web service MDL-12886 alpha web service api + alpha user core functions api + alpha Rest server (+ rest test client)

This commit is contained in:
jerome
2009-01-13 07:00:26 +00:00
parent 94c224619c
commit dee7b68b35
12 changed files with 894 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
<?php
/*
* Created on 01/12/2008
*
* Moodle base webservice api
*
* @author Jerome Mouneyrac
*/
/**
* DO NOT USE ANYTHING FROM THIS FILE - WORK IN PROGRESS
*/
abstract class moodle_ws_api {
protected $descriptions;
/**
* Constructor - We set the description of this API in order to be access by Web service
*/
function __construct () {
$this->descriptions = array();
}
/**
*
* @param <type> $functionname
*/
function get_function_webservice_description($functionname) {
if (key_exists($functionname, $this->descriptions)) {
return $this->descriptions[$functionname];
}
else {
return false;
}
}
function get_descriptions() {
return $this->descriptions;
}
}
?>
+218
View File
@@ -0,0 +1,218 @@
<?php
/**
* Created on 01/12/2008
*
* user core api
*
* @author Jerome Mouneyrac
*/
/**
* DO NOT USE ANYTHING FROM THIS FILE - WORK IN PROGRESS
*/
final class user_api {
/**
* Returns a subset of users (DO NOT COUNT)
* @global object $DB
* @param string $sort A SQL snippet for the sorting criteria to use
* @param string $recordsperpage how many records do pages have
* @param string $page which page to return (starts from 0)
* @param string $fields A comma separated list of fields to be returned from the chosen table.
* @param object $selectioncriteria:
* ->search string A simple string to search for
* ->confirmed bool A switch to allow/disallow unconfirmed users
* ->exceptions array(int) A list of IDs to ignore, eg 2,4,5,8,9,10
* ->firstinitial string ?
* ->lastinitial string ?
* @return array|false Array of {@link $USER} objects. False is returned if an error is encountered.
*/
static function tmp_namedparams_get_users($sort='firstname ASC', $recordsperpage=999999, $page=0, $fields='*', $selectioncriteria=NULL) {
global $DB;
///WS: convert array into an object
if (!empty($selectioncriteria) && is_array($selectioncriteria)) {
$selectioncriteria = (object) $selectioncriteria;
}
$LIKE = $DB->sql_ilike();
$fullname = $DB->sql_fullname();
$select = " username <> :guest AND deleted = 0";
$params = array('guest'=>'guest');
if (!empty($selectioncriteria->search)){
$selectioncriteria->search = trim($selectioncriteria->search);
$select .= " AND ($fullname $LIKE :search1 OR email $LIKE :search2 OR username = :search3)";
$params['search1'] = "%".$selectioncriteria->search."%";
$params['search2'] = "%".$selectioncriteria->search."%";
$params['search3'] = $selectioncriteria->search;
}
if (!empty($selectioncriteria->confirmed)) {
$select .= " AND confirmed = 1";
}
if (!empty($selectioncriteria->exceptions)) {
list($selectioncriteria->exceptions, $eparams) = $DB->get_in_or_equal($selectioncriteria->exceptions, SQL_PARAMS_NAMED, 'ex0000', false);
$params = $params + $eparams;
$except = " AND id ".$selectioncriteria->exceptions;
}
if (!empty($selectioncriteria->firstinitial)) {
$select .= " AND firstname $LIKE :fni";
$params['fni'] = $selectioncriteria->firstinitial."%";
}
if (!empty($selectioncriteria->lastinitial)) {
$select .= " AND lastname $LIKE :lni";
$params['lni'] = $selectioncriteria->lastinitial."%";
}
if (!empty($selectioncriteria->extraselect)) {
$select .= " AND ".$selectioncriteria->extraselect;
if (empty($selectioncriteria->extraparams)){
$params = $params + (array)$selectioncriteria->extraparams;
}
}
return $DB->get_records_select('user', $select, $params, $sort, $fields, $page, $recordsperpage);
}
/**
* Returns a subset of users
*
* @uses $CFG
* @param bool $get If false then only a count of the records is returned
* @param string $search A simple string to search for
* @param bool $confirmed A switch to allow/disallow unconfirmed users
* @param array(int) $exceptions A list of IDs to ignore, eg 2,4,5,8,9,10
* @param string $sort A SQL snippet for the sorting criteria to use
* @param string $firstinitial ?
* @param string $lastinitial ?
* @param string $page ?
* @param string $recordsperpage ?
* @param string $fields A comma separated list of fields to be returned from the chosen table.
* @return object|false|int {@link $USER} records unless get is false in which case the integer count of the records found is returned. False is returned if an error is encountered.
*/
static function tmp_get_users($get=true, $search='', $confirmed=false, array $exceptions=null, $sort='firstname ASC',
$firstinitial='', $lastinitial='', $page='', $recordsperpage='', $fields='*', $extraselect='', array $extraparams=null) {
global $DB;
if ($get && !$recordsperpage) {
debugging('Call to get_users with $get = true no $recordsperpage limit. ' .
'On large installations, this will probably cause an out of memory error. ' .
'Please think again and change your code so that it does not try to ' .
'load so much data into memory.', DEBUG_DEVELOPER);
}
$LIKE = $DB->sql_ilike();
$fullname = $DB->sql_fullname();
$select = " username <> :guest AND deleted = 0";
$params = array('guest'=>'guest');
if (!empty($search)){
$search = trim($search);
$select .= " AND ($fullname $LIKE :search1 OR email $LIKE :search2 OR username = :search3)";
$params['search1'] = "%$search%";
$params['search2'] = "%$search%";
$params['search3'] = "$search";
}
if ($confirmed) {
$select .= " AND confirmed = 1";
}
if ($exceptions) {
list($exceptions, $eparams) = $DB->get_in_or_equal($exceptions, SQL_PARAMS_NAMED, 'ex0000', false);
$params = $params + $eparams;
$except = " AND id $exceptions";
}
if ($firstinitial) {
$select .= " AND firstname $LIKE :fni";
$params['fni'] = "$firstinitial%";
}
if ($lastinitial) {
$select .= " AND lastname $LIKE :lni";
$params['lni'] = "$lastinitial%";
}
if ($extraselect) {
$select .= " AND $extraselect";
$params = $params + (array)$extraparams;
}
if ($get) {
return $DB->get_records_select('user', $select, $params, $sort, $fields, $page, $recordsperpage);
} else {
return $DB->count_records_select('user', $select, $params);
}
}
/**
* Creates an User with given information. Required fields are:
* -username
* -idnumber
* -firstname
* -lastname
* -email
*
* And there's some interesting fields:
* -password
* -auth
* -confirmed
* -timezone
* -country
* -emailstop
* -theme
* -lang
* -mailformat
*
* @param assoc array or object $user
*
* @return userid or thrown exceptions
*/
static function tmp_create_user($user) {
global $CFG, $DB;
///WS: convert user array into an user object
if (is_array($user)) {
$user = (object) $user;
}
///check password and auth fields
if (!isset($user->password)) {
$user->password = '';
}
if (!isset($user->auth)) {
$user->auth = 'manual';
}
$required = array('username','firstname','lastname','email');
foreach ($required as $req) {
if (!isset($user->{$req})) {
throw new moodle_exception('missingerequiredfield');
}
}
$record = create_user_record($user->username, $user->password, $user->auth);
if ($record) {
$user->id = $record->id;
if ($DB->update_record('user',$user)) {
return $record->id;
} else {
$DB->delete_record('user',array('id' => $record->id));
}
}
throw new moodle_exception('couldnotcreateuser');
}
}
?>
+63
View File
@@ -0,0 +1,63 @@
<?php
/**
* Created on 05/03/2008
*
* users webservice api
*
* @author Jerome Mouneyrac
*/
require_once(dirname(dirname(__FILE__)) . '/lib/moodlewsapi.php');
/**
* WORK IN PROGRESS
*/
final class user_ws_api extends moodle_ws_api {
/**
* Constructor - We set the description of this API in order to be access by Web service
*/
function __construct () {
$this->descriptions = array();
///The desciption of the web service
///
///'wsparams' and 'return' are used to described the web services to the end user (can build WSDL file from these information)
///'paramorder' is used internally by developers implementing a new protocol. It contains the params of the called function in a good order and with default value
///
///Note: web services param names have not importance. However 'paramorder' must match the function params order.
///And all web services param names defined into 'wsparams' should be included into 'paramorder' (otherwise they will not be used)
///
///How to define an object/array attribut web service parameter: 'any object/array name' + _ + 'attribut/key name'. 'attribut/key name' must match the real attribut name.
///e.g: a function has a parameter that is an object with a attribut named 'username'. You will need to declare 'anyobjectname_username' into 'wsparams'.
/// Then 'paramorder'=> array('anyobjectname' => array('username' => ...));
///
///TODO: manage object->object parameter
$this->descriptions['tmp_get_users'] = array( 'wsparams' => array('search'=> PARAM_RAW),
'return' => array('user', array('id' => PARAM_RAW, 'auth' => PARAM_RAW, 'confirmed' => PARAM_RAW, 'username' => PARAM_RAW, 'idnumber' => PARAM_RAW,
'firstname' => PARAM_RAW, 'lastname' => PARAM_RAW, 'email' => PARAM_RAW, 'emailstop' => PARAM_RAW,
'lang' => PARAM_RAW, 'theme' => PARAM_RAW, 'timezone' => PARAM_RAW, 'mailformat' => PARAM_RAW)),
'paramorder' => array('get' => true, 'search' => '', 'confirmed' => false, 'exceptions' =>null, 'sort' => 'firstname ASC',
'firstinitial' => '', 'lastinitial' => '', 'page' => '', 'recordsperpage' => '',
'fields' => 'id, auth, confirmed, username, idnumber, firstname, lastname, email, emailstop, lang, theme, timezone, mailformat',
'extraselect' => '', 'extraparams' => null));
$this->descriptions['tmp_create_user'] = array( 'wsparams' => array('user:username'=> PARAM_RAW, 'user:firstname'=> PARAM_RAW, 'user:lastname'=> PARAM_RAW, 'user:email'=> PARAM_RAW, 'user:password'=> PARAM_RAW),
'return' => array('userid', PARAM_RAW),
'paramorder' => array('user' => array('username' => null, 'firstname' => null, 'lastname'=> null, 'email'=> null, 'password'=>'')));
$this->descriptions['tmp_namedparams_get_users'] = array( 'wsparams' => array('selectioncriteria:search'=> PARAM_RAW),
'return' => array('user', array('id' => PARAM_RAW, 'auth' => PARAM_RAW, 'confirmed' => PARAM_RAW, 'username' => PARAM_RAW, 'idnumber' => PARAM_RAW,
'firstname' => PARAM_RAW, 'lastname' => PARAM_RAW, 'email' => PARAM_RAW, 'emailstop' => PARAM_RAW,
'lang' => PARAM_RAW, 'theme' => PARAM_RAW, 'timezone' => PARAM_RAW, 'mailformat' => PARAM_RAW)),
'paramorder' => array('sort' => 'firstname ASC', '$recordsperpage' => 999999, 'page' => 0,
'fields' => 'id, auth, confirmed, username, idnumber, firstname, lastname, email, emailstop, lang, theme, timezone, mailformat',
'selectioncriteria' => array('search' => '')));
}
}
?>
+127
View File
@@ -0,0 +1,127 @@
<?php
/**
*
* Rest library
*
* @author Jerome Mouneyrac, Ferran Recio, David Castro Garcia
*/
/**
*
* @author Jerome Mouneyrac
* @global object $CFG
* @param string $rest_arguments example: /mod/forum/get_discussion
* @return string xml object
*/
function call_moodle_function ($rest_arguments) {
global $CFG;
///REST params conversion
$functionname = substr($rest_arguments,strrpos($rest_arguments,"/")+1); //retrieve the function name (it's located after the last '/') in $rest_arguments
//$rest_argument
$apipath = substr($rest_arguments,0, strlen($rest_arguments) - strlen($functionname)); //api path is the other part of $rest_arguments
$classname = str_replace('/', '_', $apipath); // convert '/' into '_' (e.g. /mod/forum/ => _mod_forum_)
$classname = substr($classname,1, strlen($classname) - 1); //remove first _ (e.g. _mod_forum => mod_forum)
$coreclassname = $classname."api";
$classname .= 'ws_api';
///these three next lines can be generic => create a function
require_once($CFG->dirroot.$apipath.'wsapi.php');
$api = new $classname();
$description = $api->get_function_webservice_description($functionname); //retrieve the web service description for this function
///This following line is only REST protocol
$params = retrieve_params ($description); //retrieve the REST params
///Generic part to any protocols
if ($params === false) {
//return an error message, the REST params doesn't match with the web service description
}
require_once($CFG->dirroot.$apipath.'api.php');
$res = call_user_func_array ( $coreclassname.'::'.$functionname, $params);
///Transform result into xml in order to send the REST response
$return = mdl_conn_rest_object_to_xml ($res,$description['return'][0]);
return "<Result>$return</Result>";
}
/**
*
* @author Jerome Mouneyrac
* @param <type> $description
* @return <type>
*/
function retrieve_params ($description) {
$params = $description['paramorder'];
//retrieve REST param matching the description
foreach ($description['wsparams'] as $paramname => $paramtype) {
varlog('--retrieve_params--');
varlog($paramname);
$value = optional_param($paramname,null,$paramtype);
varlog($value);
if (!empty($value)) {
$fullstopposition = strrpos($paramname,":");
varlog(substr($paramname,0,$fullstopposition));
varlog(substr($paramname,$fullstopposition+1, strlen($paramname) - $fullstopposition));
//case: param is an object/array
if (!empty($fullstopposition)) {
$params[substr($paramname,0,$fullstopposition)][substr($paramname,$fullstopposition+1, strlen($paramname) - $fullstopposition)] = $value;
} else {
$params[$paramname] = $value;
}
}
}
varlog($params);
return $params;
}
/**
* auxiliar function for simplexml_object_to_xml
* @author Ferran Recio, David Castro Garcia
* @param $obj
* @param $tag
* @param $atts assoc array (key => value)
* @return string
*/
function mdl_conn_rest_object_to_xml ($obj, $tag,$atts=false) {
$res = '';
$tag_atts = '';
if ($atts) {
$main_atts = array();
foreach ($atts as $att=>$val) {
$main_atts[] = "$att=\"".urlencode($val)."\"";
}
if (count($main_atts)) $tag_atts = ' '.implode(' ',$main_atts);
}
//if is an object
if (is_object($obj)) {
$parts = get_object_vars($obj);
foreach ($parts as $tag2 => $val) {
$res.= mdl_conn_rest_object_to_xml ($val, $tag2);
}
return "<$tag$tag_atts>\n$res</$tag>\n";
}
//if it's an array all elements will be inside te same tag but with a new atribute key
if (is_array($obj)){
if (!$atts) $atts = array();
//we came from another array
if (isset($atts['keys'])) $atts = array();
foreach ($obj as $key=>$val) {
$array_atts = $atts;
$array_atts['key'] = $key;
$res.= mdl_conn_rest_object_to_xml ($val, $tag,$array_atts);
}
return $res;
}
//any other type, just encapsule it
$obj = htmlentities($obj);
return "<$tag$tag_atts>$obj</$tag>\n";
}
?>
+24
View File
@@ -0,0 +1,24 @@
<?php
/**
* Created on 10/14/2008
*
* REST Moodle server.
*
* NOTE: for this first implementation, REST requires implicit url encoded params.
* It uses function get_file_argument to get them.
*
* @author Jerome Mouneyrac
* @author Ferran Recio
* @author David Castro Garcia
*/
require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
require_once('lib.php');
//retrieve path and function name from the URL
$rest_arguments = get_file_argument('server.php');
header ("Content-type: text/xml");
echo call_moodle_function($rest_arguments);
?>
@@ -0,0 +1,18 @@
<?php
/**
* Created on 10/17/2008
*
* Rest Test Client configuration file
*
* @author David Castro Garcia
* @author Ferran Recio Calderó
* @author Jerome Mouneyrac
*
*/
require_once("../../../config.php");
require_once ('lib.php');
$CFG->serverurl = $CFG->wwwroot.'/webservice/rest/server.php';
if (!function_exists('curl_init')) die ('CURL library was not found!');
?>
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* Created on 10/17/2008
*
* Rest Test Client
*
* @author David Castro Garcia
* @author Ferran Recio Calderó
* @author Jerome Mouneyrac
*/
require_once ('config_rest.php');
start_interface("Create A User");
$ch = curl_init();
$data['user:username'] = "jerome4";
$data['user:firstname'] = "jerome4";
$data['user:lastname'] = "jerome4";
$data['user:email'] = "[email protected]";
var_dump($data);
curl_setopt($ch, CURLOPT_URL, $CFG->serverurl.'/user/tmp_create_user');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, format_postdata($data));
$out = curl_exec($ch);
$res = basicxml_xml_to_object($out);
show_object($res->userid);
show_xml ($out);
end_interface();
?>
+55
View File
@@ -0,0 +1,55 @@
<?php
/**
* Created on 10/17/2008
*
* Rest Test Client
*
* @author David Castro Garcia
* @author Ferran Recio Calderó
* @author Jerome Mouneyrac
*/
require_once ('config_rest.php');
$params = array('search');
foreach ($params as $param) {
$$param = (isset($_POST[$param]))?$_POST[$param]:'';
}
start_interface("List of Users");
?>
<form action="getusers.php" method="post">
<table border="0">
<tr><td>Search: </td><td><input type="text" name="search" value="<?php echo $search; ?>"/></td></tr>
<tr><td></td><td><input type="submit" value="Find Users"></td></tr>
</table>
</form>
<?php
if ($search) {
$data['search'] = $search;
var_dump($CFG->serverurl.'/user/tmp_get_users');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $CFG->serverurl.'/user/tmp_get_users');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, format_postdata($data));
$out = curl_exec($ch);
$res = basicxml_xml_to_object($out);
show_object($res->user,2,'auth');
show_xml ($out);
} else {
echo "<p>Fill the form first</p>";
}
end_interface();
?>
+27
View File
@@ -0,0 +1,27 @@
<?php
/**
* Created on 10/17/2008
*
* Rest Test Client
*
* @author David Castro Garcia
* @author Ferran Recio Calderó
* @author Jerome Mouneyrac
*/
require_once ('config_rest.php');
start_interface (false);
$links = array( array('getusers.php','getusers()'),
array('createuser.php','createuser()'),
array('namedparams_get_users.php','namedparams_get_users()'));
echo '<ul>';
foreach ($links as $link) {
echo '<li><a href="'.$link[0].'">'.$link[1].'</a></li>';
}
echo '</ul>';
end_interface(false);
?>
+224
View File
@@ -0,0 +1,224 @@
<?php
/**
* Created on 10/17/2008
*
* Rest Test Client Suport Library
*
* @author David Castro Garcia
* @author Ferran Recio Calderó
*/
//--- interface helpers ---
/**
* starts the interface
*/
function start_interface ($title="&nbsp;") {
$title2 = ($title)?$title:"&nbsp;";
echo '<html><head>';
echo "<title>Moodle Webservice Rest Test Client</title>";
echo '<link rel="stylesheet" href="style.css" type="text/css">';
echo '</head><body>';
echo '<div class="head"><h1>Moodle Webservice Rest Test Client</h1>';
echo "<h3>$title2</h3>";
echo '</div>';
echo '<div class="content">';
if ($title) echo '<p class="return"><a href="index.php"><img src="return.gif" border="0"/></a></p>';
}
/**
* end interface
*
* @param bool $ret=true: show return button
*/
function end_interface ($ret = true) {
if ($ret) echo '<p class="return"><a href="index.php"><img src="return.gif" border="0"/></a></p>';
echo '</div>';
echo '<div class="footer">Created by David Castro i Ferran Recio for Moodle Webservices</div>';
echo '</body></html>';
}
/**
* print XML div area
*
* @param string $xml
*
*/
function show_xml ($xml) {
echo '<div class="xmlshow">';
echo '<a onClick="document.getElementById(\'toogleme\').style.display = ' .
'(document.getElementById(\'toogleme\').style.display!=\'none\')?\'none\':\'\';">Hide/Show XML</a>';
echo "<div style=\"display:none;\" id=\"toogleme\">";
echo '<pre>';echo htmlentities($xml);echo '</pre>';
echo "</div>";
echo "</div>";
}
/**
* format post data
*/
function format_postdata ($data) {
$o="";
foreach ($data as $k=>$v) {
$o.= "$k=".rawurlencode($v)."&";
}
$post_data=substr($o,0,-1);
return $post_data;
}
/**
* shows an object in list format
*
* @param mixed $obj
* @param integer $cols: number of colums
* @ string string $check=false: if this attribute is not present, the $obj is ans error
*
*/
function show_object ($obj,$cols=1,$check=false) {
if (!is_array($obj)) $obj = array($obj);
echo '<ul class="results">';
foreach ($obj as $r) {
if ($check && (!isset($r->$check) || $r->$check==-1)) {
echo '<li class="error">';
echo "EMPTY ROW!";
} else {
if (is_object($r)) {
echo '<li class="element">';
$text = array();
$parts = get_object_vars($r);
$num = 1;
$currline = '';
foreach ($parts as $key => $val) {
$currline.= "<span class=\"resultval\"><b>$key:</b> <i>$val</i></span>, ";
if ($num >= $cols) {
$currline=substr($currline,0,-2);
$text[] = $currline;
$currline = '';
$num = 0;
}
$num++;
}
echo implode('<br/>',$text);
} else {
if ($r==-1 || !$r) {
echo '<li class="error">';
echo "EMPTY ROW!";
} else {
echo '<li class="element">';
echo "<span class=\"resultval\"><b>Returned Value:</b> <i>$r</i></span>";
}
}
}
echo '</li>';
}
echo '</ul>';
}
//---- XML simple parser ----
//this code was donated by Ferran Recio
/**
* convert a simple xml into php object
*
* @author ferran recio
*
* @param String $xml
*
* @return mixed
*/
function basicxml_xml_to_object ($xml) {
$xml=utf8_encode($xml);
//create the parser
$parser = xml_parser_create ();
xml_set_default_handler ($parser,'basicxml_xml_to_object_aux');
$values = array();
$index = array();
xml_parse_into_struct($parser,$xml,$values,$index);
//print_object($values);
//print_object($index);
//just simplexml tag (disabled)
//if (strtolower($values[0]['tag']) != 'basicxml') return false;
//if (strtolower($values[count($values)-1]['tag']) != 'basicxml') return false;
$res = basicxml_xml_to_object_aux ($values);
//omit the first tag
$parts = array_keys(get_object_vars($res));
$key = $parts[0];
return $res->$key;
}
/**
* auxiliar function to basicxml_xml_to_object
*
* @author ferran recio
*
* @param mixed $values
*
* @return mixed
*/
function basicxml_xml_to_object_aux ($values) {
if (!is_array($values)) return false;
//print_object ($values);
$currset = array();
$search = false;
foreach ($values as $value) {
$tag = strtolower($value['tag']);
//if we are acomulating, just acomulate it
if ($search) {
//if it closes a tag, we just stop searching
if ($tag == $search && $value['type']=='close') {
//recursivity
$obj2 = basicxml_xml_to_object_aux ($currset);
//search cleaning
$search = false;
//add to result
if (isset($res->{$tag})){
if (is_array($res->{$tag})){
$res->{$tag}[] = $obj2;
} else {
$res->{$tag} = array($res->{$tag},$obj2);
}
} else {
$res->{$tag} = $obj2;
}
} else {
//we are searching. If it's cdada, pass it throw
if ($value['type']=='cdata') continue;
//if isn't cdata, put it in the set and continue searching
//(because isn't the close we're searching)
$currset[] = $value;
}
} else {
//walking the xml
if ($value['type']=='open'){
//on open, let's search on it
$currset = array();
$search = $tag;
} else {
//if it's complete just save it
if ($value['type']=='complete') {
$val = html_entity_decode($value['value']);
if (isset($res->{$tag})){
if (is_array($res->{$tag})){
$res->{$tag}[] = $val;
} else {
$res->{$tag} = array($res->{$tag},$val);
}
} else {
$res->{$tag} = $val;
}
}
}
}
}
return $res;
}
?>
Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

+57
View File
@@ -0,0 +1,57 @@
body {
background-color: #FAFFFF;;
}
.xmlshow {
background-color: #DDDDFF;
padding:20px;
}
.xmlshow div {
height: 200px;
overflow: auto;
padding: 20px;
background-color: #EEEEFF;
}
.head, .footer {
background-color: #AAAAFF;
text-align: center;
}
.footer {
font-size: small;
padding: 10px;
}
.content {
padding-left: 20px;
padding-right: 20px;
}
.results li{
margin-bottom:20px;
padding: 10px;
list-style-type: square;
}
.element {
background-color: #CCCCFF;
}
.element span:hover{
background-color:#DDDDFF;
}
.error {
background-color: #FFCCCC;
}
.return a, .return a:hover, .return a:visited{
color:#0000DD;
}
h1, h2 {
margin:0px;
padding:5px;
}