summaryrefslogtreecommitdiff
path: root/lib/querypath/src/QueryPath.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/querypath/src/QueryPath.php')
-rw-r--r--lib/querypath/src/QueryPath.php356
1 files changed, 356 insertions, 0 deletions
diff --git a/lib/querypath/src/QueryPath.php b/lib/querypath/src/QueryPath.php
new file mode 100644
index 0000000..2013377
--- /dev/null
+++ b/lib/querypath/src/QueryPath.php
@@ -0,0 +1,356 @@
+<?php
+/** @file
+ * The Query Path package provides tools for manipulating a structured document.
+ * Typically, the sort of structured document is one using a Document Object Model
+ * (DOM).
+ * The two major DOMs are the XML DOM and the HTML DOM. Using Query Path, you can
+ * build, parse, search, and modify DOM documents.
+ *
+ * To use QueryPath, only one file must be imported: qp.php. This file defines
+ * the `qp()` function, and also registers an autoloader if necessary.
+ *
+ * Standard usage:
+ * @code
+ * <?php
+ * require 'qp.php';
+ *
+ * $xml = '<?xml version="1.0"?><test><foo id="myID"/></test>';
+ *
+ * // Procedural call a la jQuery:
+ * $qp = qp($xml, '#myID');
+ * $qp->append('<new><elements/></new>')->writeHTML();
+ *
+ * // Object-oriented version with a factory:
+ * $qp = QueryPath::with($xml)->find('#myID')
+ * $qp->append('<new><elements/></new>')->writeHTML();
+ * ?>
+ * @endcode
+ *
+ * The above would print (formatted for readability):
+ * @code
+ * <?xml version="1.0"?>
+ * <test>
+ * <foo id="myID">
+ * <new>
+ * <element/>
+ * </new>
+ * </foo>
+ * </test>
+ * @endcode
+ *
+ * ## Discovering the Library
+ *
+ * To gain familiarity with QueryPath, the following three API docs are
+ * the best to start with:
+ *
+ *- qp(): This function constructs new queries, and is the starting point
+ * for manipulating a document. htmlqp() is an alias tuned for HTML
+ * documents (especially old HTML), and QueryPath::with(), QueryPath::withXML()
+ * and QueryPath::withHTML() all perform a similar role, but in a purely
+ * object oriented way.
+ *- QueryPath: This is the top-level class for the library. It defines the
+ * main factories and some useful functions.
+ *- QueryPath::Query: This defines all of the functions in QueryPath. When
+ * working with HTML and XML, the QueryPath::DOMQuery is the actual
+ * implementation that you work with.
+ *
+ * Included with the source code for QueryPath is a complete set of unit tests
+ * as well as some example files. Those are good resources for learning about
+ * how to apply QueryPath's tools. The full API documentation can be generated
+ * from these files using Doxygen, or you can view it online at
+ * http://api.querypath.org.
+ *
+ * If you are interested in building extensions for QueryPath, see the
+ * QueryPath and QueryPath::Extension classes. There you will find information on adding
+ * your own tools to QueryPath.
+ *
+ * QueryPath also comes with a full CSS 3 selector implementation (now
+ * with partial support for the current draft of the CSS 4 selector spec). If
+ * you are interested in reusing that in other code, you will want to start
+ * with QueryPath::CSS::EventHandler.php, which is the event interface for the parser.
+ *
+ * All of the code in QueryPath is licensed under an MIT-style license
+ * license. All of the code is Copyright, 2012 by Matt Butcher.
+ *
+ * @author M Butcher <matt @aleph-null.tv>
+ * @license MIT
+ * @see QueryPath
+ * @see qp()
+ * @see http://querypath.org The QueryPath home page.
+ * @see http://api.querypath.org An online version of the API docs.
+ * @see http://technosophos.com For how-tos and examples.
+ * @copyright Copyright (c) 2009-2012, Matt Butcher.
+ * @version -UNSTABLE% (3.x.x)
+ *
+ */
+
+use \Masterminds\HTML5;
+
+/**
+ *
+ */
+class QueryPath {
+ /**
+ * The version string for this version of QueryPath.
+ *
+ * Standard releases will be of the following form: <MAJOR>.<MINOR>[.<PATCH>][-STABILITY].
+ *
+ * Examples:
+ * - 2.0
+ * - 2.1.1
+ * - 2.0-alpha1
+ *
+ * Developer releases will always be of the form dev-<DATE>.
+ *
+ * @since 2.0
+ */
+ const VERSION = '3.0.x';
+
+ /**
+ * Major version number.
+ *
+ * Examples:
+ * - 3
+ * - 4
+ *
+ * @since 3.0.1
+ */
+ const VERSION_MAJOR = 3;
+
+ /**
+ * This is a stub HTML 4.01 document.
+ *
+ * <b>Using {@link QueryPath::XHTML_STUB} is preferred.</b>
+ *
+ * This is primarily for generating legacy HTML content. Modern web applications
+ * should use QueryPath::XHTML_STUB.
+ *
+ * Use this stub with the HTML familiy of methods (QueryPath::Query::html(),
+ * QueryPath::Query::writeHTML(), QueryPath::Query::innerHTML()).
+ */
+ const HTML_STUB = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+ <html lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Untitled</title>
+ </head>
+ <body></body>
+ </html>';
+
+ const HTML5_STUB = '<!DOCTYPE html>
+ <html>
+ <head>
+ <title>Untitled</title>
+ </head>
+ <body></body>
+ </html>';
+
+ /**
+ * This is a stub XHTML document.
+ *
+ * Since XHTML is an XML format, you should use XML functions with this document
+ * fragment. For example, you should use {@link xml()}, {@link innerXML()}, and
+ * {@link writeXML()}.
+ *
+ * This can be passed into {@link qp()} to begin a new basic HTML document.
+ *
+ * Example:
+ * @code
+ * $qp = qp(QueryPath::XHTML_STUB); // Creates a new XHTML document
+ * $qp->writeXML(); // Writes the document as well-formed XHTML.
+ * @endcode
+ * @since 2.0
+ */
+ const XHTML_STUB = '<?xml version="1.0"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title>Untitled</title>
+ </head>
+ <body></body>
+ </html>';
+
+
+ public static function with($document = NULL, $selector = NULL, $options = array()) {
+ $qpClass = isset($options['QueryPath_class']) ? $options['QueryPath_class'] : '\QueryPath\DOMQuery';
+
+ $qp = new $qpClass($document, $selector, $options);
+ return $qp;
+ }
+
+ public static function withXML($source = NULL, $selector = NULL, $options = array()) {
+ $options += array(
+ 'use_parser' => 'xml',
+ );
+ return self::with($source, $selector, $options);
+ }
+
+ public static function withHTML($source = NULL, $selector = NULL, $options = array()) {
+ // Need a way to force an HTML parse instead of an XML parse when the
+ // doctype is XHTML, since many XHTML documents are not valid XML
+ // (because of coding errors, not by design).
+
+ $options += array(
+ 'ignore_parser_warnings' => TRUE,
+ 'convert_to_encoding' => 'ISO-8859-1',
+ 'convert_from_encoding' => 'auto',
+ //'replace_entities' => TRUE,
+ 'use_parser' => 'html',
+ // This is stripping actually necessary low ASCII.
+ //'strip_low_ascii' => TRUE,
+ );
+ return @self::with($source, $selector, $options);
+ }
+
+ /**
+ * Parse HTML5 documents.
+ *
+ * This uses HTML5-PHP to parse the document. In actuality, this parser does
+ * a fine job with pre-HTML5 documents in most cases, though really old HTML
+ * (like 2.0) may have some substantial quirks.
+ *
+ * <b>Supported Options</b>
+ * Any options supported by HTML5-PHP are allowed here. Additionally, the
+ * following options have meaning to QueryPath.
+ * - QueryPath_class
+ *
+ *
+ * @param mixed $source
+ * A document as an HTML string, or a path/URL. For compatibility with
+ * existing functions, a DOMDocument, SimpleXMLElement, DOMNode or array
+ * of DOMNodes will be passed through as well. However, these types are not
+ * validated in any way.
+ *
+ * @param string $selector
+ * A CSS3 selector.
+ *
+ * @param array $options
+ * An associative array of options, which is passed on into HTML5-PHP. Note
+ * that the standard QueryPath options may be ignored for this function,
+ * since it uses a different parser.
+ *
+ * @return QueryPath
+ */
+ public static function withHTML5($source = NULL, $selector = NULL, $options = array()) {
+ $qpClass = isset($options['QueryPath_class']) ? $options['QueryPath_class'] : '\QueryPath\DOMQuery';
+
+ if(is_string($source)) {
+ $html5 = new HTML5();
+ if (strpos($source, '<') !== FALSE && strpos($source, '>') !== FALSE) {
+ $source = $html5->loadHTML($source);
+ }
+ else {
+ $source = $html5->load($source);
+ }
+ }
+
+ $qp = new $qpClass($source, $selector, $options);
+ return $qp;
+ }
+
+ /**
+ * Enable one or more extensions.
+ *
+ * Extensions provide additional features to QueryPath. To enable and
+ * extension, you can use this method.
+ *
+ * In this example, we enable the QPTPL extension:
+ * @code
+ * <?php
+ * QueryPath::enable('\QueryPath\QPTPL');
+ * ?>
+ * @endcode
+ *
+ * Note that the name is a fully qualified class name.
+ *
+ * We can enable more than one extension at a time like this:
+ *
+ * @code
+ * <?php
+ * $extensions = array('\QueryPath\QPXML', '\QueryPath\QPDB');
+ * QueryPath::enable($extensions);
+ * ?>
+ * @endcode
+ *
+ * @attention If you are not using an autoloader, you will need to
+ * manually `require` or `include` the files that contain the
+ * extensions.
+ *
+ * @param mixed $extensionNames
+ * The name of an extension or an array of extension names.
+ * QueryPath assumes that these are extension class names,
+ * and attempts to register these as QueryPath extensions.
+ */
+ public static function enable($extensionNames) {
+
+ if (is_array($extensionNames)) {
+ foreach ($extensionNames as $extension) {
+ \QueryPath\ExtensionRegistry::extend($extension);
+ }
+ }
+ else {
+ \QueryPath\ExtensionRegistry::extend($extensionNames);
+ }
+ }
+
+ /**
+ * Get a list of all of the enabled extensions.
+ *
+ * This example dumps a list of extensions to standard output:
+ * @code
+ * <?php
+ * $extensions = QueryPath::enabledExtensions();
+ * print_r($extensions);
+ * ?>
+ * @endcode
+ *
+ * @return array
+ * An array of extension names.
+ *
+ * @see QueryPath::ExtensionRegistry
+ */
+ public static function enabledExtensions() {
+ return \QueryPath\ExtensionRegistry::extensionNames();
+ }
+
+
+
+ /**
+ * A static function for transforming data into a Data URL.
+ *
+ * This can be used to create Data URLs for injection into CSS, JavaScript, or other
+ * non-XML/HTML content. If you are working with QP objects, you may want to use
+ * dataURL() instead.
+ *
+ * @param mixed $data
+ * The contents to inject as the data. The value can be any one of the following:
+ * - A URL: If this is given, then the subsystem will read the content from that URL. THIS
+ * MUST BE A FULL URL, not a relative path.
+ * - A string of data: If this is given, then the subsystem will encode the string.
+ * - A stream or file handle: If this is given, the stream's contents will be encoded
+ * and inserted as data.
+ * (Note that we make the assumption here that you would never want to set data to be
+ * a URL. If this is an incorrect assumption, file a bug.)
+ * @param string $mime
+ * The MIME type of the document.
+ * @param resource $context
+ * A valid context. Use this only if you need to pass a stream context. This is only necessary
+ * if $data is a URL. (See {@link stream_context_create()}).
+ * @return
+ * An encoded data URL.
+ */
+ public static function encodeDataURL($data, $mime = 'application/octet-stream', $context = NULL) {
+ if (is_resource($data)) {
+ $data = stream_get_contents($data);
+ }
+ elseif (filter_var($data, FILTER_VALIDATE_URL)) {
+ $data = file_get_contents($data, FALSE, $context);
+ }
+
+ $encoded = base64_encode($data);
+
+ return 'data:' . $mime . ';base64,' . $encoded;
+ }
+
+}