1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
#include <gcj/cni.h>
#include <java/io/ByteArrayInputStream.h>
#include <java/lang/System.h>
#include <java/lang/Throwable.h>
#include <java/util/ArrayList.h>
#include <javax/xml/xpath/XPath.h>
#include <javax/xml/xpath/XPathFactory.h>
#include <javax/xml/xpath/XPathExpression.h>
#include <javax/xml/xpath/XPathConstants.h>
#include <javax/xml/parsers/DocumentBuilderFactory.h>
#include <javax/xml/parsers/DocumentBuilder.h>
#include <org/w3c/dom/Attr.h>
#include <org/w3c/dom/Document.h>
#include <org/w3c/dom/Element.h>
#include <org/w3c/dom/NodeList.h>
#include <org/w3c/dom/NamedNodeMap.h>
#include <org/xml/sax/InputSource.h>
#include "nu/validator/htmlparser/dom/HtmlDocumentBuilder.h"
#include "DomUtils.h"
#include "ruby.h"
using namespace java::io;
using namespace java::lang;
using namespace java::util;
using namespace javax::xml::parsers;
using namespace javax::xml::xpath;
using namespace nu::validator::htmlparser::dom;
using namespace org::w3c::dom;
using namespace org::xml::sax;
static VALUE jaxp_Document;
static VALUE jaxp_Attr;
static VALUE jaxp_Element;
static ID ID_read;
static ID ID_doc;
static ID ID_element;
// convert a Java string into a Ruby string
static VALUE j2r(String *string) {
if (string == NULL) return Qnil;
jint len = JvGetStringUTFLength(string);
char buf[len];
JvGetStringUTFRegion(string, 0, len, buf);
return rb_str_new(buf, len);
}
// convert a Ruby string into a Java string
static String *r2j(VALUE string) {
return JvNewStringUTF(RSTRING(string)->ptr);
}
// release the Java Document associated with this Ruby Document
static void vnu_document_free(Document *doc) {
DomUtils::unpin(doc);
}
// Nu::Validator::parse( string|file )
static VALUE vnu_parse(VALUE self, VALUE input) {
HtmlDocumentBuilder *parser = new HtmlDocumentBuilder();
// read file-like objects into memory. TODO: buffer such objects
if (rb_respond_to(input, ID_read))
input = rb_funcall(input, ID_read, 0);
// convert input in to a ByteArrayInputStream
jbyteArray bytes = JvNewByteArray(RSTRING(input)->len);
memcpy(elements(bytes), RSTRING(input)->ptr, RSTRING(input)->len);
InputSource *source = new InputSource(new ByteArrayInputStream(bytes));
// parse, pin, and wrap
Document *doc = parser->parse(source);
DomUtils::pin(doc);
return Data_Wrap_Struct(jaxp_Document, NULL, vnu_document_free, doc);
}
// Jaxp::parse( string|file )
static VALUE jaxp_parse(VALUE self, VALUE input) {
DocumentBuilderFactory *factory = DocumentBuilderFactory::newInstance();
DocumentBuilder *parser = factory->newDocumentBuilder();
// read file-like objects into memory. TODO: buffer such objects
if (rb_respond_to(input, ID_read))
input = rb_funcall(input, ID_read, 0);
try {
jbyteArray bytes = JvNewByteArray(RSTRING(input)->len);
memcpy(elements(bytes), RSTRING(input)->ptr, RSTRING(input)->len);
Document *doc = parser->parse(new ByteArrayInputStream(bytes));
DomUtils::pin(doc);
return Data_Wrap_Struct(jaxp_Document, NULL, vnu_document_free, doc);
} catch (java::lang::Throwable *ex) {
ex->printStackTrace();
return Qnil;
}
}
// Nu::Validator::Document#encoding
static VALUE jaxp_document_encoding(VALUE rdoc) {
Document *jdoc;
Data_Get_Struct(rdoc, Document, jdoc);
return j2r(jdoc->getXmlEncoding());
}
// Nu::Validator::Document#root
static VALUE jaxp_document_root(VALUE rdoc) {
Document *jdoc;
Data_Get_Struct(rdoc, Document, jdoc);
Element *jelement = jdoc->getDocumentElement();
if (jelement==NULL) return Qnil;
VALUE relement = Data_Wrap_Struct(jaxp_Element, NULL, NULL, jelement);
rb_ivar_set(relement, ID_doc, rdoc);
return relement;
}
// Nu::Validator::Document#xpath
static VALUE jaxp_document_xpath(VALUE rdoc, VALUE path) {
Document *jdoc;
Data_Get_Struct(rdoc, Document, jdoc);
Element *jelement = jdoc->getDocumentElement();
if (jelement==NULL) return Qnil;
XPath *xpath = XPathFactory::newInstance()->newXPath();
XPathExpression *expr = xpath->compile(r2j(path));
NodeList *list = (NodeList*) expr->evaluate(jdoc, XPathConstants::NODESET);
VALUE result = rb_ary_new();
for (int i=0; i<list->getLength(); i++) {
VALUE relement = Data_Wrap_Struct(jaxp_Element, NULL, NULL, list->item(i));
rb_ivar_set(relement, ID_doc, rdoc);
rb_ary_push(result, relement);
}
return result;
}
// Nu::Validator::Element#name
static VALUE jaxp_element_name(VALUE relement) {
Element *jelement;
Data_Get_Struct(relement, Element, jelement);
return j2r(jelement->getNodeName());
}
// Nu::Validator::Element#attributes
static VALUE jaxp_element_attributes(VALUE relement) {
Element *jelement;
Data_Get_Struct(relement, Element, jelement);
VALUE result = rb_hash_new();
NamedNodeMap *map = jelement->getAttributes();
for (int i=0; i<map->getLength(); i++) {
Attr *jattr = (Attr *) map->item(i);
VALUE rattr = Data_Wrap_Struct(jaxp_Attr, NULL, NULL, jattr);
rb_ivar_set(rattr, ID_element, relement);
rb_hash_aset(result, j2r(jattr->getName()), rattr);
}
return result;
}
// Nu::Validator::Attribute#value
static VALUE jaxp_attribute_value(VALUE rattribute) {
Attr *jattribute;
Data_Get_Struct(rattribute, Attr, jattribute);
return j2r(jattribute->getValue());
}
typedef VALUE (ruby_method)(...);
// Nu::Validator module initialization
extern "C" void Init_validator() {
JvCreateJavaVM(NULL);
JvAttachCurrentThread(NULL, NULL);
JvInitClass(&DomUtils::class$);
JvInitClass(&XPathFactory::class$);
JvInitClass(&XPathConstants::class$);
VALUE jaxp = rb_define_module("Jaxp");
rb_define_singleton_method(jaxp, "parse", (ruby_method*)&jaxp_parse, 1);
VALUE nu = rb_define_module("Nu");
VALUE validator = rb_define_module_under(nu, "Validator");
rb_define_singleton_method(validator, "parse", (ruby_method*)&vnu_parse, 1);
jaxp_Document = rb_define_class_under(jaxp, "Document", rb_cObject);
rb_define_method(jaxp_Document, "encoding",
(ruby_method*)&jaxp_document_encoding, 0);
rb_define_method(jaxp_Document, "root",
(ruby_method*)&jaxp_document_root, 0);
rb_define_method(jaxp_Document, "xpath",
(ruby_method*)&jaxp_document_xpath, 1);
jaxp_Element = rb_define_class_under(jaxp, "Element", rb_cObject);
rb_define_method(jaxp_Element, "name",
(ruby_method*)&jaxp_element_name, 0);
rb_define_method(jaxp_Element, "attributes",
(ruby_method*)&jaxp_element_attributes, 0);
jaxp_Attr = rb_define_class_under(jaxp, "Attr", rb_cObject);
rb_define_method(jaxp_Attr, "value",
(ruby_method*)&jaxp_attribute_value, 0);
ID_read = rb_intern("read");
ID_doc = rb_intern("@doc");
ID_element = rb_intern("@element");
}
|