Browse Source

add relaxNG support

set xml base directory so it is consistant
add validation examples
PHP-5.0
Rob Richards 22 years ago
parent
commit
80fd6dcaa4
  1. 8
      ext/xmlreader/examples/dtdexample.dtd
  2. 15
      ext/xmlreader/examples/dtdexample.xml
  3. 11
      ext/xmlreader/examples/relaxNG.rng
  4. 1
      ext/xmlreader/examples/relaxNG.xml
  5. 23
      ext/xmlreader/examples/relaxNG2.rng
  6. 8
      ext/xmlreader/examples/relaxNG3.rng
  7. 25
      ext/xmlreader/examples/xmlreader_relaxNG.php
  8. 18
      ext/xmlreader/examples/xmlreader_validatedtd.php
  9. 180
      ext/xmlreader/php_xmlreader.c
  10. 1
      ext/xmlreader/php_xmlreader.h

8
ext/xmlreader/examples/dtdexample.dtd

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT LIST (MOVIE+)>
<!ELEMENT MOVIE (TITLE, ORGTITLE, LOC, INFO)>
<!ATTLIST MOVIE ID ID #REQUIRED>
<!ELEMENT TITLE (#PCDATA)>
<!ELEMENT ORGTITLE (#PCDATA)>
<!ELEMENT LOC (#PCDATA)>
<!ELEMENT INFO (#PCDATA)>

15
ext/xmlreader/examples/dtdexample.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE LIST SYSTEM "dtdexample.dtd">
<LIST>
<MOVIE ID="x200338360">
<TITLE>Move Title 1</TITLE>
<ORGTITLE/><LOC>Location 1</LOC>
<INFO/>
</MOVIE>
<MOVIE ID="m200338361">
<TITLE>Move Title 2</TITLE>
<ORGTITLE/>
<LOC>Location 2</LOC>
<INFO/>
</MOVIE>
</LIST>

11
ext/xmlreader/examples/relaxNG.rng

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<include href="relaxNG2.rng">
<define name="TEI.prose"><ref name="INCLUDE"/></define>
</include>
</grammar>

1
ext/xmlreader/examples/relaxNG.xml

@ -0,0 +1 @@
<TEI.2>hello</TEI.2>

23
ext/xmlreader/examples/relaxNG2.rng

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:t="http://www.thaiopensource.com/ns/annotations" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<ref name="TEI.2"/>
</start>
<define name="IGNORE">
<notAllowed/>
</define>
<define name="INCLUDE">
<empty/>
</define>
<include href="relaxNG3.rng"/>
<define name="TEI.2">
<element name="TEI.2">
<text/>
</element>
</define>
</grammar>

8
ext/xmlreader/examples/relaxNG3.rng

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:t="http://www.thaiopensource.com/ns/annotations" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<define name="TEI.prose" combine="interleave">
<ref name="IGNORE"/>
</define>
</grammar>

25
ext/xmlreader/examples/xmlreader_relaxNG.php

@ -0,0 +1,25 @@
<?php
$indent = 5; /* Number of spaces to indent per level */
$reader = new XMLReader();
$reader->open('relaxNG.xml');
/*
Example setting relaxNG using string:
$reader->setRelaxNGSchemaSource(file_get_contents('relaxNG.rng'));
*/
if ($reader->setRelaxNGSchema('relaxNG.rng')) {
while ($reader->read()) {
/* Print node name indenting it based on depth and $indent var */
print str_repeat(" ", $reader->depth * $indent).$reader->name."\n";
}
}
print "\n";
if (! $reader->isValid()) {
print "Document is not valid\n";
} else {
print "Document is valid\n";
}
?>

18
ext/xmlreader/examples/xmlreader_validatedtd.php

@ -0,0 +1,18 @@
<?php
$indent = 5; /* Number of spaces to indent per level */
$xml = new XMLReader();
$xml->open("dtdexample.xml");
$xml->setParserProperty(XMLREADER_LOADDTD, TRUE);
$xml->setParserProperty(XMLREADER_VALIDATE, TRUE);
while($xml->read()) {
/* Print node name indenting it based on depth and $indent var */
print str_repeat(" ", $xml->depth * $indent).$xml->name."\n";
if ($xml->hasAttributes) {
$attCount = $xml->attributeCount;
print str_repeat(" ", $xml->depth * $indent)." Number of Attributes: ".$xml->attributeCount."\n";
}
}
print "\n\nValid:\n";
var_dump($xml->isValid());
?>

180
ext/xmlreader/php_xmlreader.c

@ -47,6 +47,9 @@ typedef struct _xmlreader_prop_handler {
int type;
} xmlreader_prop_handler;
#define XMLREADER_LOAD_STRING 0
#define XMLREADER_LOAD_FILE 1
static void xmlreader_register_prop_handler(HashTable *prop_handler, char *name, xmlreader_read_int_t read_int_func, xmlreader_read_char_t read_char_func, int rettype TSRMLS_DC)
{
xmlreader_prop_handler hnd;
@ -178,6 +181,97 @@ void xmlreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
}
/* }}} */
/* _xmlreader_get_valid_file_path and _xmlreader_get_relaxNG should be made a
common function in libxml extension as code is common to a few xml extensions */
char *_xmlreader_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len TSRMLS_DC) {
xmlURI *uri;
xmlChar *escsource;
char *file_dest;
int isFileUri = 0;
uri = xmlCreateURI();
escsource = xmlURIEscapeStr(source, ":");
xmlParseURIReference(uri, escsource);
xmlFree(escsource);
if (uri->scheme != NULL) {
/* absolute file uris - libxml only supports localhost or empty host */
if (strncasecmp(source, "file:///",8) == 0) {
isFileUri = 1;
#ifdef PHP_WIN32
source += 8;
#else
source += 7;
#endif
} else if (strncasecmp(source, "file://localhost/",17) == 0) {
isFileUri = 1;
#ifdef PHP_WIN32
source += 17;
#else
source += 16;
#endif
}
}
file_dest = source;
if ((uri->scheme == NULL || isFileUri)) {
/* XXX possible buffer overflow if VCWD_REALPATH does not know size of resolved_path */
if (! VCWD_REALPATH(source, resolved_path)) {
expand_filepath(source, resolved_path TSRMLS_CC);
}
file_dest = resolved_path;
}
xmlFreeURI(uri);
return file_dest;
}
#ifdef LIBXML_SCHEMAS_ENABLED
static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, int source_len, int type,
xmlRelaxNGValidityErrorFunc error_func,
xmlRelaxNGValidityWarningFunc warn_func TSRMLS_DC)
{
char *valid_file = NULL;
xmlRelaxNGParserCtxtPtr parser = NULL;
xmlRelaxNGPtr sptr;
char resolved_path[MAXPATHLEN + 1];
switch (type) {
case XMLREADER_LOAD_FILE:
valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
if (!valid_file) {
return NULL;
}
parser = xmlRelaxNGNewParserCtxt(valid_file);
break;
case XMLREADER_LOAD_STRING:
parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
/* If loading from memory, we need to set the base directory for the document
but it is not apparent how to do that for schema's */
break;
default:
return NULL;
}
if (parser == NULL) {
return NULL;
}
if (error_func || warn_func) {
xmlRelaxNGSetParserErrors(parser,
(xmlRelaxNGValidityErrorFunc) error_func,
(xmlRelaxNGValidityWarningFunc) warn_func,
parser);
}
sptr = xmlRelaxNGParse(parser);
xmlRelaxNGFreeParserCtxt(parser);
return sptr;
}
#endif
/* {{{ xmlreader_module_entry
*/
zend_module_entry xmlreader_module_entry = {
@ -216,6 +310,12 @@ static void xmlreader_free_resources(xmlreader_object *intern) {
xmlFreeTextReader(intern->ptr);
intern->ptr = NULL;
}
#ifdef LIBXML_SCHEMAS_ENABLED
if (intern->schema) {
xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
intern->schema = NULL;
}
#endif
}
}
@ -246,6 +346,7 @@ zend_object_value xmlreader_objects_new(zend_class_entry *class_type TSRMLS_DC)
intern->std.in_set = 0;
intern->ptr = NULL;
intern->input = NULL;
intern->schema = NULL;
intern->prop_handler = &xmlreader_prop_handlers;
ALLOC_HASHTABLE(intern->std.properties);
@ -329,6 +430,58 @@ static void php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAMETERS, xmlreader_
}
*/
static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int type) {
#ifdef LIBXML_SCHEMAS_ENABLED
zval *id;
int source_len = 0, retval = -1;
xmlreader_object *intern;
xmlRelaxNGPtr schema = NULL;
char *source;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!", &source, &source_len) == FAILURE) {
return;
}
if (source != NULL && !source_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Schema data source is requried");
RETURN_FALSE;
}
id = getThis();
intern = (xmlreader_object *)zend_object_store_get_object(id TSRMLS_CC);
if (intern && intern->ptr) {
if (source) {
schema = _xmlreader_get_relaxNG(source, source_len, type, NULL, NULL TSRMLS_CC);
if (schema) {
retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, schema);
}
} else {
/* unset the associated relaxNG context and schema if one exists */
retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, NULL);
}
if (retval == 0) {
if (intern->schema) {
xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
}
intern->schema = schema;
RETURN_TRUE;
}
}
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set schema. This must be set prior to reading or schema contains errors.");
RETURN_FALSE;
#else
php_error_docref(NULL TSRMLS_CC, E_WARNING, "No Schema support built into libxml.");
RETURN_FALSE;
#endif
}
/* {{{ proto boolean close()
Closes xmlreader - current frees resources until xmlTextReaderClose is fixed in libxml */
PHP_METHOD(xmlreader, close)
@ -610,7 +763,8 @@ PHP_METHOD(xmlreader, open)
zval *id;
int source_len = 0;
xmlreader_object *intern;
char *source;
char *source, *valid_file = NULL;
char resolved_path[MAXPATHLEN + 1];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &source, &source_len) == FAILURE) {
return;
@ -627,7 +781,11 @@ PHP_METHOD(xmlreader, open)
xmlreader_free_resources(intern);
intern->ptr = xmlNewTextReaderFilename(source);
valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
if (valid_file) {
intern->ptr = xmlNewTextReaderFilename(valid_file);
}
if (intern->ptr == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open source data");
@ -689,6 +847,22 @@ PHP_METHOD(xmlreader, setParserProperty)
}
/* }}} */
/* {{{ proto boolean setRelaxNGSchemaSource(string filename)
Sets the string that the the XMLReader will parse. */
PHP_METHOD(xmlreader, setRelaxNGSchema)
{
php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_FILE);
}
/* }}} */
/* {{{ proto boolean setRelaxNGSchemaSource(string source)
Sets the string that the the XMLReader will parse. */
PHP_METHOD(xmlreader, setRelaxNGSchemaSource)
{
php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_STRING);
}
/* }}} */
/* {{{ proto boolean XML(string source)
Sets the string that the the XMLReader will parse. */
PHP_METHOD(xmlreader, XML)
@ -770,6 +944,8 @@ static zend_function_entry xmlreader_functions[] = {
PHP_ME(xmlreader, resetState, NULL, ZEND_ACC_PUBLIC)
*/
PHP_ME(xmlreader, setParserProperty, NULL, ZEND_ACC_PUBLIC)
PHP_ME(xmlreader, setRelaxNGSchema, NULL, ZEND_ACC_PUBLIC)
PHP_ME(xmlreader, setRelaxNGSchemaSource, NULL, ZEND_ACC_PUBLIC)
PHP_ME(xmlreader, XML, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};

1
ext/xmlreader/php_xmlreader.h

@ -44,6 +44,7 @@ typedef struct _xmlreader_object {
must manually allocate and de-allocate these - can be refactored when
libxml 2.6.x becomes minimum version */
xmlParserInputBufferPtr input;
void *schema;
HashTable *prop_handler;
zend_object_handle handle;
} xmlreader_object;

Loading…
Cancel
Save