it's alive, muahhahah
This commit is contained in:
parent
33c6a2f654
commit
091b7d1fda
306
dexter.c
306
dexter.c
|
@ -68,15 +68,6 @@ xmlDocPtr dex_parse_doc(dexPtr dex, xmlDocPtr doc) {
|
|||
return xsltApplyStylesheet(dex->stylesheet, doc, NULL);
|
||||
}
|
||||
|
||||
static contextPtr clone_context(contextPtr context) {
|
||||
contextPtr other;
|
||||
other = __dex_alloc(sizeof(dex_context));
|
||||
other->name = astrdup(context->name);
|
||||
other->group_key = astrdup(context->group_key);
|
||||
other->full_group_key = astrdup(context->full_group_key);
|
||||
return other;
|
||||
}
|
||||
|
||||
dexPtr dex_compile(char* dex_str, char* incl) {
|
||||
dexPtr dex = (dexPtr) calloc(sizeof(compiled_dex), 1);
|
||||
|
||||
|
@ -118,21 +109,16 @@ dexPtr dex_compile(char* dex_str, char* incl) {
|
|||
sprintbuf(buf, "%s\n", incl);
|
||||
sprintbuf(buf, "<xsl:template match=\"/\">\n");
|
||||
sprintbuf(buf, "<dexter:root>\n");
|
||||
|
||||
contextPtr context = new_context(json, buf);
|
||||
__dex_recurse(context);
|
||||
|
||||
contextPtr context = __dex_alloc(sizeof(dex_context));
|
||||
context->name = "root";
|
||||
context->full_group_key = "";
|
||||
context->group_key = "";
|
||||
xslt_keys = "";
|
||||
|
||||
__dex_recurse(json, buf, context);
|
||||
json_object_put(json); // frees json
|
||||
dex->error = last_dex_error;
|
||||
|
||||
sprintbuf(buf, "</dexter:root>\n");
|
||||
sprintbuf(buf, "</xsl:template>\n");
|
||||
printf("hi: %s\n", xslt_keys);
|
||||
sprintbuf(buf, xslt_keys);
|
||||
sprintbuf(buf, context->key_buf->buf);
|
||||
sprintbuf(buf, "</xsl:stylesheet>\n");
|
||||
|
||||
if(dex->error == NULL) {
|
||||
|
@ -147,6 +133,54 @@ dexPtr dex_compile(char* dex_str, char* incl) {
|
|||
return dex;
|
||||
}
|
||||
|
||||
contextPtr new_context(struct json_object * json, struct printbuf *buf) {
|
||||
contextPtr c = __dex_alloc(sizeof(dex_context));
|
||||
c->key_buf = printbuf_new();
|
||||
sprintbuf(c->key_buf, "");
|
||||
c->name = "root";
|
||||
c->tag = "root";
|
||||
c->full_expr = "/";
|
||||
c->expr = NULL;
|
||||
c->magic = NULL;
|
||||
c->filter = NULL;
|
||||
c->buf = buf;
|
||||
c->json = json;
|
||||
c->parent = NULL;
|
||||
c->array = 0;
|
||||
c->string = 0;
|
||||
c->keys = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
contextPtr deeper_context(contextPtr context, char* key, struct json_object * val) {
|
||||
contextPtr c = __dex_alloc(sizeof(dex_context));
|
||||
c->key_buf = context->key_buf;
|
||||
c->keys = context->keys;
|
||||
c->tag = __tag(key);
|
||||
c->array = json_object_is_type(val, json_type_array);
|
||||
c->json = c->array ? json_object_array_get_idx(val, 0) : val;
|
||||
c->string = json_object_is_type(c->json, json_type_string);
|
||||
c->filter = __filter(key);
|
||||
c->name = astrcat3(context->name, ".", c->tag);
|
||||
c->magic = ((c->filter == NULL) && c->array && !(c->string)) ? c->name : context->magic;
|
||||
c->buf = context->buf;
|
||||
c->expr = c->string ? myparse(astrdup(json_object_get_string(c->json))) : NULL;
|
||||
c->full_expr = full_expr(context, c->filter);
|
||||
c->full_expr = full_expr(c, c->expr);
|
||||
c->expr = filter_intersection(c->magic, c->expr);
|
||||
c->filter = filter_intersection(c->magic, c->filter);
|
||||
c->parent = context;
|
||||
return c;
|
||||
}
|
||||
|
||||
static char* filter_intersection(char* key, char* expr) {
|
||||
if(key != NULL && expr != NULL) {
|
||||
return astrcat7("set:intersection(key('", key, "__key', $", key, "__index), ", expr, ")");
|
||||
} else {
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
void dex_free(dexPtr ptr) {
|
||||
if(ptr->error != NULL) free(ptr->error);
|
||||
if(ptr->stylesheet != NULL) xsltFreeStylesheet(ptr->stylesheet);
|
||||
|
@ -157,93 +191,126 @@ void * __dex_alloc(int size) {
|
|||
return obstack_alloc(&dex_obstack, size);
|
||||
}
|
||||
|
||||
void __dex_recurse_object(struct json_object * json, struct printbuf* buf, contextPtr context) {
|
||||
json_object_object_foreach(json, key, val) {
|
||||
__dex_recurse_foreach(json, key, val, buf, context);
|
||||
}
|
||||
void yyerror(const char * s) {
|
||||
struct printbuf *buf = printbuf_new();
|
||||
if(last_dex_error !=NULL) sprintbuf(buf, "%s\n", last_dex_error);
|
||||
sprintbuf(buf, "%s in key: %s", s, dex_parsing_context->name);
|
||||
last_dex_error = strdup(buf->buf);
|
||||
printbuf_free(buf);
|
||||
}
|
||||
|
||||
static contextPtr deeper_context(contextPtr context, char* tag) {
|
||||
contextPtr deeper = clone_context(context);
|
||||
deeper->name = astrcat3(context->name, ".", tag);
|
||||
return deeper;
|
||||
}
|
||||
|
||||
void __dex_recurse_foreach(struct json_object * json, char* key, struct json_object * val, struct printbuf* buf, contextPtr context) {
|
||||
char *tag = astrdup(key);;
|
||||
char* __tag(char* key) {
|
||||
char *tag = astrdup(key);
|
||||
char *ptr = tag;
|
||||
char *expr = astrdup(key);;
|
||||
while(*ptr++ != '\0'){
|
||||
if(*ptr == '(') {
|
||||
*ptr = 0;
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
char* __filter(char* key) {
|
||||
char *expr = astrdup(key);
|
||||
char *ptr = expr;
|
||||
|
||||
int offset = 0;
|
||||
bool has_expr = false;
|
||||
struct json_object * inner;
|
||||
|
||||
|
||||
while(*ptr++ != '\0'){
|
||||
offset++;
|
||||
if(*ptr == '(') {
|
||||
*ptr = 0;
|
||||
has_expr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
expr += offset;
|
||||
|
||||
sprintbuf(buf, "<%s>\n", tag);
|
||||
switch(json_object_get_type(val)) {
|
||||
case json_type_array:
|
||||
// printf("arr");
|
||||
inner = json_object_array_get_idx(val, 0);
|
||||
switch(json_object_get_type(inner)) {
|
||||
case json_type_string:
|
||||
if(has_expr) {
|
||||
printf("parsing: %s\n", expr);
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", myparse(expr));
|
||||
printf("error: %s\n", last_dex_error);
|
||||
__dex_recurse(inner, buf, deeper_context(context, tag));
|
||||
} else {
|
||||
printf("parsing: %s\n", json_object_get_string(inner));
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", myparse(json_object_get_string(inner)));
|
||||
printf("error: %s\n", last_dex_error);
|
||||
struct json_object * dot = json_object_new_string(".");
|
||||
__dex_recurse(dot, buf, deeper_context(context, tag));
|
||||
}
|
||||
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
break;
|
||||
case json_type_object:
|
||||
if(has_expr) {
|
||||
printf("parsing: %s\n", expr);
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", myparse(expr));
|
||||
printf("error: %s\n", last_dex_error);
|
||||
__dex_recurse(inner, buf, deeper_context(context, tag));
|
||||
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
} else {
|
||||
char* inner_expr = inner_key_of(inner);
|
||||
if(inner_expr == NULL) { // boring, no singleton keys, just maintain structure
|
||||
sprintbuf(buf, "<dexter:groups><dexter:group>\n");
|
||||
__dex_recurse(inner, buf, deeper_context(context, tag));
|
||||
sprintbuf(buf, "</dexter:group></dexter:groups>\n");
|
||||
} else {
|
||||
char* group_key = myparse(inner_expr);
|
||||
contextPtr new_context = deeper_context(context, tag);
|
||||
new_context->full_group_key = astrcat3(new_context->full_group_key, "//", group_key);
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", group_key);
|
||||
sprintbuf(buf,
|
||||
"<xsl:variable name=\"%s_index\" select=\"count(set:intersection(following::*, %s))\"/>\n",
|
||||
new_context->name, new_context->full_group_key);
|
||||
__dex_recurse(inner, buf, new_context);
|
||||
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case json_type_string:
|
||||
case json_type_object:
|
||||
__dex_recurse(val, buf, deeper_context(context, tag));
|
||||
};
|
||||
sprintbuf(buf, "</%s>\n", tag);
|
||||
if(!has_expr) return NULL;
|
||||
|
||||
expr += offset + 1; // clip "("
|
||||
int l = strlen(expr);
|
||||
if(l <= 1) return NULL;
|
||||
*(expr + l - 1) = 0; // clip ")"
|
||||
return myparse(expr);
|
||||
}
|
||||
|
||||
char* inner_key_of(struct json_object * json) {
|
||||
void __dex_recurse(contextPtr context) {
|
||||
char* tmp;
|
||||
struct printbuf * buf;
|
||||
keyPtr keys;
|
||||
contextPtr c;
|
||||
json_object_object_foreach(context->json, key, val) {
|
||||
c = deeper_context(context, key, val);
|
||||
sprintbuf(c->buf, "<%s>\n", c->tag);
|
||||
if(c->string) {
|
||||
if(c->array) {
|
||||
sprintbuf(c->buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", c->expr);
|
||||
sprintbuf(c->buf, "<xsl:value-of select=\".\" />\n");
|
||||
sprintbuf(c->buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
} else {
|
||||
sprintbuf(c->buf, "<xsl:value-of select=\"%s\" />\n", c->expr);
|
||||
}
|
||||
} else { // if c->object !string
|
||||
if(c->array) { // scoped
|
||||
if(c->filter != NULL) {
|
||||
sprintbuf(c->buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", c->filter);
|
||||
__dex_recurse(c);
|
||||
sprintbuf(c->buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
} else { // magic
|
||||
sprintbuf(c->buf, "<xsl:variable name=\"%s__context\" select=\".\"/>\n", c->name);
|
||||
tmp = myparse(astrdup(inner_key_of(c->json)));
|
||||
sprintbuf(c->buf, "<dexter:groups><xsl:for-each select=\"%s\">\n", filter_intersection(context->magic, tmp));
|
||||
|
||||
|
||||
// keys
|
||||
keys = __dex_alloc(sizeof(key_node));
|
||||
keys->name = c->name;
|
||||
keys->use = full_expr(c, tmp);
|
||||
keys->next = c->keys;
|
||||
c->keys = keys;
|
||||
|
||||
buf = printbuf_new();
|
||||
|
||||
sprintbuf(buf, "concat(");
|
||||
while(keys != NULL){
|
||||
sprintbuf(buf, "count(set:intersection(following::*, %s)), '-',", keys->use);
|
||||
keys = keys->next;
|
||||
}
|
||||
sprintbuf(buf, "'')");
|
||||
tmp = astrdup(buf->buf);
|
||||
printbuf_free(buf);
|
||||
|
||||
sprintbuf(c->key_buf, "<xsl:key name=\"%s__key\" match=\"%s\" use=\"%s\"/>\n", c->name,
|
||||
full_expr(c, "./descendant-or-self::*"),
|
||||
tmp
|
||||
);
|
||||
|
||||
sprintbuf(c->buf, "<xsl:variable name=\"%s__index\" select=\"%s\"/>\n", c->name, tmp);
|
||||
sprintbuf(c->buf, "<xsl:for-each select=\"$%s__context\"><dexter:group>\n", c->name);
|
||||
__dex_recurse(c);
|
||||
sprintbuf(c->buf, "</dexter:group></xsl:for-each></xsl:for-each></dexter:groups>\n");
|
||||
}
|
||||
} else {
|
||||
if(c->filter == NULL) {
|
||||
__dex_recurse(c);
|
||||
} else {
|
||||
sprintbuf(c->buf, "<xsl:for-each select=\"%s\"><xsl:if test=\"position() = 1\">\n", c->filter);
|
||||
__dex_recurse(c);
|
||||
sprintbuf(c->buf, "</xsl:if></xsl:for-each>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
sprintbuf(c->buf, "</%s>\n", c->tag);
|
||||
}
|
||||
}
|
||||
|
||||
static char* full_expr(contextPtr context, char* expr) {
|
||||
if(expr == NULL) return context->full_expr;
|
||||
char* merged = arepl(expr, ".", context->full_expr);
|
||||
return arepl(merged, "///", "//");
|
||||
}
|
||||
|
||||
static char* inner_key_of(struct json_object * json) {
|
||||
switch(json_object_get_type(json)) {
|
||||
case json_type_string:
|
||||
return json_object_get_string(json);
|
||||
|
@ -254,65 +321,10 @@ char* inner_key_of(struct json_object * json) {
|
|||
}
|
||||
}
|
||||
|
||||
char* inner_key_each(struct json_object * json) {
|
||||
static char* inner_key_each(struct json_object * json) {
|
||||
json_object_object_foreach(json, key, val) {
|
||||
char* inner = inner_key_of(val);
|
||||
if(inner != NULL) return inner;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __dex_recurse_array(struct json_object * json, struct printbuf* buf, contextPtr context) {
|
||||
printf("WTF!!!!!!!\n");
|
||||
}
|
||||
|
||||
void __dex_recurse_string(struct json_object * json, struct printbuf* buf, contextPtr context) {
|
||||
char* a = astrdup(json_object_get_string(json));
|
||||
char* ptr = context->name;
|
||||
char* last_name = context->name;
|
||||
char* expr;
|
||||
while(*ptr++){
|
||||
if(*ptr == '.') last_name = ptr + 1;
|
||||
}
|
||||
dex_parsing_context = context;
|
||||
expr = myparse(a);
|
||||
|
||||
xslt_keys = astrcat8(xslt_keys, "<xsl:key name=\"key-",
|
||||
context->name,
|
||||
"\" match=\"",
|
||||
expr,
|
||||
"\" use=\"count(set:intersection(following::*, ",
|
||||
context->full_group_key,
|
||||
"))\" />");
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"%s\" />\n", context->name, expr);
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"$%s\" />\n", last_name, context->name);
|
||||
sprintbuf(buf, "<xsl:value-of select=\"$%s\" />\n", context->name);
|
||||
}
|
||||
|
||||
void yyerror(const char * s) {
|
||||
struct printbuf *buf = printbuf_new();
|
||||
if(last_dex_error !=NULL) sprintbuf(buf, "%s\n", last_dex_error);
|
||||
sprintbuf(buf, "%s in key: %s", s, dex_parsing_context->name);
|
||||
last_dex_error = strdup(buf->buf);
|
||||
printbuf_free(buf);
|
||||
}
|
||||
|
||||
void __dex_recurse(struct json_object * json, struct printbuf* buf, contextPtr context) {
|
||||
switch(json_object_get_type(json)){
|
||||
case json_type_object:
|
||||
__dex_recurse_object(json, buf, context);
|
||||
break;
|
||||
case json_type_array:
|
||||
__dex_recurse_array(json, buf, context);
|
||||
break;
|
||||
case json_type_string:
|
||||
__dex_recurse_string(json, buf, context);
|
||||
break;
|
||||
case json_type_boolean:
|
||||
case json_type_double:
|
||||
case json_type_int:
|
||||
default:
|
||||
fprintf(stderr, "Invalid type in json\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
57
dexter.h
57
dexter.h
|
@ -24,20 +24,30 @@ typedef struct __compiled_dex {
|
|||
char* error;
|
||||
} compiled_dex;
|
||||
|
||||
typedef struct __dex_context {
|
||||
typedef struct __key_node {
|
||||
char* name;
|
||||
char* group_key;
|
||||
char* full_group_key;
|
||||
char* use;
|
||||
struct __key_node * next;
|
||||
} key_node;
|
||||
|
||||
typedef key_node * keyPtr;
|
||||
|
||||
typedef struct __dex_context {
|
||||
struct printbuf * buf;
|
||||
struct printbuf * key_buf;
|
||||
keyPtr keys;
|
||||
struct json_object * json;
|
||||
struct __dex_context * parent;
|
||||
char* tag;
|
||||
char* filter;
|
||||
char* expr;
|
||||
char* full_expr;
|
||||
char* name;
|
||||
char* magic;
|
||||
int array;
|
||||
int string;
|
||||
} dex_context;
|
||||
|
||||
static char* xslt_keys;
|
||||
|
||||
// typedef struct __dex_context_node {
|
||||
// char* key;
|
||||
// dex_context_node* next;
|
||||
// } dex_context_node;
|
||||
//
|
||||
// typedef dex_context_node * nodePtr;
|
||||
typedef compiled_dex * dexPtr;
|
||||
typedef dex_context * contextPtr;
|
||||
|
||||
|
@ -50,15 +60,28 @@ xmlDocPtr dex_parse_string(dexPtr, char*, size_t, boolean);
|
|||
|
||||
static xmlDocPtr dex_parse_doc(dexPtr, xmlDocPtr);
|
||||
|
||||
void print_variables(struct printbuf *, contextPtr, char*);
|
||||
void* __dex_alloc(int);
|
||||
static char* full_expr(contextPtr, char*);
|
||||
static char* expr_join(char*, char*);
|
||||
static char* inner_key_of(struct json_object *);
|
||||
static char* inner_key_each(struct json_object *);
|
||||
static void free_context(contextPtr);
|
||||
static contextPtr init_context();
|
||||
static contextPtr clone_context(contextPtr);
|
||||
static contextPtr deeper_context(contextPtr, char*);
|
||||
static void __dex_recurse(struct json_object *, struct printbuf*, contextPtr);
|
||||
static void __dex_recurse_object(struct json_object *, struct printbuf*, contextPtr);
|
||||
static void __dex_recurse_array(struct json_object *, struct printbuf*, contextPtr);
|
||||
static void __dex_recurse_string(struct json_object *, struct printbuf*, contextPtr);
|
||||
static void __dex_recurse_foreach(struct json_object *, char *, struct json_object *, struct printbuf *, contextPtr);
|
||||
static contextPtr tagged_context(contextPtr, char*);
|
||||
|
||||
contextPtr new_context(struct json_object *, struct printbuf *);
|
||||
contextPtr deeper_context(contextPtr, char*, struct json_object *);
|
||||
|
||||
static char* __tag(char* key);
|
||||
static char* __filter(char* key);
|
||||
static void __dex_recurse(contextPtr);
|
||||
static void __dex_keys(contextPtr);
|
||||
static char* filter_intersection(char*, char*);
|
||||
|
||||
static char* inner_key_of(struct json_object *);
|
||||
|
||||
static char* inner_key_each(struct json_object *);
|
||||
|
||||
#endif
|
|
@ -11,5 +11,4 @@
|
|||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
|
@ -143,7 +143,7 @@
|
|||
<xsl:key name="post-key" match="//*[@id='posts']//li/descendant-or-self::*"
|
||||
use="concat(count(set:intersection(following::*, //h1)) , '-', count(set:intersection(following::*, //*[@id='posts']//li//h2)))" />
|
||||
<xsl:key name="comment-key" match="//*[@id='posts']//li/descendant-or-self::*"
|
||||
use="concat(count(set:intersection(following::*, //h1)), '-',
|
||||
use="concat(count(set:intersection(following::*, 4)), '-',
|
||||
count(set:intersection(following::*, //*[@id='posts']//li//h2)), '-',
|
||||
count(set:intersection(following::*, //*[@id='posts']//li//*[@id='comments']//h3)))" />
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<body>
|
||||
<h4>a</h4>
|
||||
<p>a1</p>
|
||||
<p>a2</p>
|
||||
<p>a3</p>
|
||||
<h4>b</h4>
|
||||
<p>b1</p>
|
||||
<p>b2</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,48 @@
|
|||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dexter="http://kylemaxwell.com/dexter" xmlns:str="http://exslt.org/strings" xmlns:set="http://exslt.org/sets" xmlns:math="http://exslt.org/math" xmlns:func="http://exslt.org/functions" xmlns:user="http://kylemaxwell.com/dexter/user-functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:date="http://exslt.org/dates-and-times" xmlns:exsl="http://exslt.org/common" xmlns:saxon="http://icl.com/saxon" version="1.0" extension-element-prefixes="str math set func dyn exsl saxon user date">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
<xsl:strip-space elements="*"/>
|
||||
<xsl:template match="/">
|
||||
<dexter:root>
|
||||
<day>
|
||||
<dexter:groups>
|
||||
<xsl:for-each select=".//b/h4">
|
||||
<dexter:group>
|
||||
<title><xsl:value-of select="key('hafter', last() - position())"/></title>
|
||||
<entries>
|
||||
<dexter:groups>
|
||||
<xsl:for-each select="key('pafter', last() - position())">
|
||||
<xsl:if test="position() < 5">
|
||||
<dexter:group><xsl:value-of select="."/></dexter:group>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</dexter:groups>
|
||||
</entries>
|
||||
|
||||
<nest>
|
||||
<dexter:groups>
|
||||
<xsl:for-each select="//b">
|
||||
<xsl:if test="position() < 5">
|
||||
<dexter:group><xsl:value-of select="."/></dexter:group>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</dexter:groups>
|
||||
</nest>
|
||||
|
||||
</dexter:group>
|
||||
</xsl:for-each>
|
||||
</dexter:groups>
|
||||
</day>
|
||||
</dexter:root>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:key name="hafter" match="//b/h4" use="count(following::b/h4)" />
|
||||
<xsl:key name="pafter" match="//p/a" use="count(following::b/h4)" />
|
||||
<xsl:key name="bafter" match="//b" use="count(following::b/h4)" />
|
||||
</xsl:stylesheet>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -3,39 +3,14 @@
|
|||
<xsl:output method="xml" indent="yes"/>
|
||||
<xsl:strip-space elements="*"/>
|
||||
|
||||
<!--
|
||||
{
|
||||
"page": [{
|
||||
"title": "h1",
|
||||
"nav": ["ul#nav li"],
|
||||
"post(#posts li)": [{
|
||||
"title": "h2",
|
||||
"paras": ["p"],
|
||||
"comments": [{
|
||||
"title": "#comments h3",
|
||||
"paras": ["#comments p"]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
-->
|
||||
|
||||
<xsl:template match="node()">
|
||||
<xsl:copy>
|
||||
<xsl:attribute name="index"><xsl:value-of select="concat(count(set:intersection(following::*, //h1)), '-',
|
||||
count(set:intersection(following::*, //*[@id='posts']//li//h2)), '-',
|
||||
count(set:intersection(following::*, //*[@id='posts']//li//*[@id='comments']//h3)))" /></xsl:attribute>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
<xsl:copy>
|
||||
<xsl:attribute name="index"><xsl:value-of select="concat(count(set:intersection(following::*, //h1)), '-','')" /></xsl:attribute>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="@*" mode="copy">
|
||||
<xsl:copy-of select="."/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="@*">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
|
||||
</xsl:stylesheet>
|
18
kstring.c
18
kstring.c
|
@ -3,9 +3,27 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "kstring.h"
|
||||
#include "printbuf.h"
|
||||
#include "obstack.h"
|
||||
#include "dexter.h"
|
||||
|
||||
char* arepl(char* orig, char* old, char* new) {
|
||||
char* ptr = astrdup(orig);
|
||||
int nlen = strlen(new);
|
||||
int olen = strlen(old);
|
||||
char* i;
|
||||
struct printbuf * buf = printbuf_new();
|
||||
while((i = strstr(ptr, old)) != NULL) {
|
||||
printbuf_memappend(buf, ptr, i - ptr);
|
||||
printbuf_memappend(buf, new, nlen);
|
||||
ptr = i + olen;
|
||||
}
|
||||
printbuf_memappend(buf, ptr, strlen(ptr));
|
||||
ptr = astrdup(buf->buf);
|
||||
printbuf_free(buf);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char* astrdup(char* c) {
|
||||
if(c == NULL) return NULL;
|
||||
return astrcat(c, "");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef KSTRING_INCLUDED
|
||||
#define KSTRING_INCLUDED
|
||||
extern char* arepl(char*, char*, char*);
|
||||
extern char* astrdup(char*);
|
||||
extern char* astrcat(char*, char*);
|
||||
extern char* astrcat3(char*, char*, char*);
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <argp.h>
|
||||
#include <json/json.h>
|
||||
#include "kstring.h"
|
||||
#include "obstack.h"
|
||||
#include "dexter.h"
|
||||
#include "y.tab.h"
|
||||
#include "printbuf.h"
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <libxslt/xslt.h>
|
||||
#include <libxslt/xsltInternals.h>
|
||||
#include <libxslt/transform.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/HTMLparser.h>
|
||||
#include <libxml/HTMLtree.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libexslt/exslt.h>
|
||||
|
||||
int yywrap(void){
|
||||
return 1;
|
||||
}
|
||||
|
||||
xmlDocPtr dex_parse_file(dexPtr dex, char* file, boolean html) {
|
||||
if(html) {
|
||||
htmlParserCtxtPtr htmlCtxt = htmlNewParserCtxt();
|
||||
htmlDocPtr html = htmlCtxtReadFile(htmlCtxt, file, "UTF-8", 3);
|
||||
if(html == NULL) {
|
||||
asprintf(&dex->error, "Couldn't parse file: %s\n", file);
|
||||
return NULL;
|
||||
}
|
||||
return dex_parse_doc(dex, html);
|
||||
} else {
|
||||
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
|
||||
xmlDocPtr xml = xmlCtxtReadFile(ctxt, file, "UTF-8", 3);
|
||||
if(xml == NULL) {
|
||||
asprintf(&dex->error, "Couldn't parse file: %s\n", file);
|
||||
return NULL;
|
||||
}
|
||||
return dex_parse_doc(dex, xml);
|
||||
}
|
||||
}
|
||||
|
||||
xmlDocPtr dex_parse_string(dexPtr dex, char* string, size_t size, boolean html) {
|
||||
if(html) {
|
||||
htmlParserCtxtPtr htmlCtxt = htmlNewParserCtxt();
|
||||
htmlDocPtr html = htmlCtxtReadMemory(htmlCtxt, string, size, "http://foo", "UTF-8", 3);
|
||||
if(html == NULL) {
|
||||
asprintf(&dex->error, "Couldn't parse string\n");
|
||||
return NULL;
|
||||
}
|
||||
return dex_parse_doc(dex, html);
|
||||
} else {
|
||||
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
|
||||
xmlDocPtr xml = xmlCtxtReadMemory(ctxt, string, size, "http://foo", "UTF-8", 3);
|
||||
if(xml == NULL) {
|
||||
asprintf(&dex->error, "Couldn't parse string\n");
|
||||
return NULL;
|
||||
}
|
||||
return dex_parse_doc(dex, xml);
|
||||
}
|
||||
}
|
||||
|
||||
xmlDocPtr dex_parse_doc(dexPtr dex, xmlDocPtr doc) {
|
||||
return xsltApplyStylesheet(dex->stylesheet, doc, NULL);
|
||||
}
|
||||
|
||||
static contextPtr clone_context(contextPtr context) {
|
||||
contextPtr other;
|
||||
other = __dex_alloc(sizeof(dex_context));
|
||||
other->name = astrdup(context->name);
|
||||
other->expr = astrdup(context->expr);
|
||||
other->keys = clone_list(context->keys);
|
||||
return other;
|
||||
}
|
||||
|
||||
static contextPtr tagged_context(contextPtr context, char* tag) {
|
||||
contextPtr other = clone_context(context);
|
||||
other->name = astrcat3(context->name, ".", tag);
|
||||
return other;
|
||||
}
|
||||
|
||||
static contextPtr init_context() {
|
||||
contextPtr other;
|
||||
other = __dex_alloc(sizeof(dex_context));
|
||||
other->name = "root";
|
||||
other->expr = "/";
|
||||
other->keys = NULL;
|
||||
return other;
|
||||
}
|
||||
|
||||
static char* inner_key_of(struct json_object * json) {
|
||||
switch(json_object_get_type(json)) {
|
||||
case json_type_string:
|
||||
return json_object_get_string(json);
|
||||
case json_type_array:
|
||||
return NULL;
|
||||
case json_type_object:
|
||||
return inner_key_each(json);
|
||||
}
|
||||
}
|
||||
|
||||
static char* inner_key_each(struct json_object * json) {
|
||||
json_object_object_foreach(json, key, val) {
|
||||
char* inner = inner_key_of(val);
|
||||
if(inner != NULL) return inner;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static strsPtr clone_list(strsPtr list) {
|
||||
if(list == NULL) return NULL;
|
||||
strsPtr other = __dex_alloc(sizeof(strs));
|
||||
other->direction = list->direction;
|
||||
other->name = astrdup(list->name);
|
||||
other->expr = astrdup(list->expr);
|
||||
other->next = clone_list(list->next);
|
||||
return other;
|
||||
}
|
||||
|
||||
dexPtr dex_compile(char* dex_str, char* incl) {
|
||||
dexPtr dex = (dexPtr) calloc(sizeof(compiled_dex), 1);
|
||||
|
||||
if(last_dex_error != NULL) {
|
||||
free(last_dex_error);
|
||||
last_dex_error = NULL;
|
||||
}
|
||||
|
||||
if(!dex_exslt_registered) {
|
||||
exsltRegisterAll();
|
||||
dex_exslt_registered = true;
|
||||
}
|
||||
|
||||
obstack_init(&dex_obstack);
|
||||
|
||||
struct json_object *json = json_tokener_parse(dex_str);
|
||||
if(is_error(json)) {
|
||||
dex->error = strdup("Your dex is not valid json.");
|
||||
return dex;
|
||||
}
|
||||
|
||||
struct printbuf* buf = printbuf_new();
|
||||
|
||||
sprintbuf(buf, "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"");
|
||||
sprintbuf(buf, " xmlns:dexter=\"http://kylemaxwell.com/dexter\"");
|
||||
sprintbuf(buf, " xmlns:str=\"http://exslt.org/strings\"");
|
||||
sprintbuf(buf, " xmlns:set=\"http://exslt.org/sets\"");
|
||||
sprintbuf(buf, " xmlns:math=\"http://exslt.org/math\"");
|
||||
sprintbuf(buf, " xmlns:func=\"http://exslt.org/functions\"");
|
||||
sprintbuf(buf, " xmlns:user=\"http://kylemaxwell.com/dexter/user-functions\"");
|
||||
sprintbuf(buf, " xmlns:dyn=\"http://exslt.org/dynamic\"");
|
||||
sprintbuf(buf, " xmlns:date=\"http://exslt.org/dates-and-times\"");
|
||||
sprintbuf(buf, " xmlns:exsl=\"http://exslt.org/common\"");
|
||||
sprintbuf(buf, " xmlns:saxon=\"http://icl.com/saxon\"");
|
||||
sprintbuf(buf, " extension-element-prefixes=\"str math set func dyn exsl saxon user date\"");
|
||||
sprintbuf(buf, ">\n");
|
||||
sprintbuf(buf, "<xsl:output method=\"xml\" indent=\"yes\"/>\n");
|
||||
sprintbuf(buf, "<xsl:strip-space elements=\"*\"/>\n");
|
||||
sprintbuf(buf, "%s\n", incl);
|
||||
sprintbuf(buf, "<xsl:template match=\"/\">\n");
|
||||
sprintbuf(buf, "<dexter:root>\n");
|
||||
|
||||
contextPtr context = init_context();
|
||||
xslt_keys = "<!-- keys -->";
|
||||
next_context = 0;
|
||||
|
||||
__dex_simple_single_object(json, buf, context);
|
||||
|
||||
json_object_put(json); // frees json
|
||||
dex->error = last_dex_error;
|
||||
|
||||
sprintbuf(buf, "</dexter:root>\n");
|
||||
sprintbuf(buf, "</xsl:template>\n");
|
||||
sprintbuf(buf, xslt_keys);
|
||||
sprintbuf(buf, "</xsl:stylesheet>\n");
|
||||
|
||||
if(dex->error == NULL) {
|
||||
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
|
||||
xmlDocPtr doc = xmlCtxtReadMemory(ctxt, buf->buf, buf->size, "http://kylemaxwell.com/some-dex", "UTF-8", 3);
|
||||
dex->stylesheet = xsltParseStylesheetDoc(doc);
|
||||
}
|
||||
|
||||
printbuf_free(buf);
|
||||
obstack_free(&dex_obstack, NULL);
|
||||
|
||||
return dex;
|
||||
}
|
||||
|
||||
void dex_free(dexPtr ptr) {
|
||||
if(ptr->error != NULL) free(ptr->error);
|
||||
if(ptr->stylesheet != NULL) xsltFreeStylesheet(ptr->stylesheet);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void * __dex_alloc(int size) {
|
||||
return obstack_alloc(&dex_obstack, size);
|
||||
}
|
||||
|
||||
void yyerror(const char * s) {
|
||||
struct printbuf *buf = printbuf_new();
|
||||
if(last_dex_error !=NULL) sprintbuf(buf, "%s\n", last_dex_error);
|
||||
sprintbuf(buf, "%s in key: %s", s, dex_parsing_context->name);
|
||||
last_dex_error = strdup(buf->buf);
|
||||
printbuf_free(buf);
|
||||
}
|
||||
|
||||
char* __tag(char* key) {
|
||||
char *tag = astrdup(key);
|
||||
char *ptr = tag;
|
||||
while(*ptr++ != '\0'){
|
||||
if(*ptr == '(') {
|
||||
*ptr = 0;
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
char* __filter(char* key) {
|
||||
char *expr = astrdup(key);
|
||||
char *ptr = expr;
|
||||
|
||||
int offset = 0;
|
||||
bool has_expr = false;
|
||||
|
||||
while(*ptr++ != '\0'){
|
||||
offset++;
|
||||
if(*ptr == '(') {
|
||||
has_expr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!has_expr) return NULL;
|
||||
|
||||
expr += offset + 1; // clip "("
|
||||
int l = strlen(expr);
|
||||
if(l <= 1) return NULL;
|
||||
*(expr + l - 1) = 0; // clip ")"
|
||||
return myparse(expr);
|
||||
}
|
||||
|
||||
void __dex_simple_single_object(struct json_object * json, struct printbuf* buf, contextPtr orig_context) {
|
||||
char* tag;
|
||||
char* filter;
|
||||
struct json_object * inner;
|
||||
int contains_object;
|
||||
contextPtr context;
|
||||
json_object_object_foreach(json, key, val) {
|
||||
// printf("a\n");
|
||||
tag = __tag(key);
|
||||
filter = __filter(key);
|
||||
sprintbuf(buf, "<%s>\n", tag);
|
||||
// printf("b\n");
|
||||
context = tagged_context(orig_context, tag);
|
||||
switch(json_object_get_type(val)){
|
||||
case json_type_object:
|
||||
if(filter) {
|
||||
// printf("c\n");
|
||||
printf("WTF!\n");
|
||||
} else {
|
||||
// printf("d\n");
|
||||
__dex_simple_single_object(val, buf, context);
|
||||
}
|
||||
break;
|
||||
case json_type_string:
|
||||
if(filter != NULL) {
|
||||
printf("WTF!!!!!!!\n");
|
||||
} else {
|
||||
// printf("e\n");
|
||||
__dex_simple_single_string(val, buf, context);
|
||||
}
|
||||
break;
|
||||
case json_type_array:
|
||||
// printf("q: %s\n", filter);
|
||||
inner = json_object_array_get_idx(val, 0);
|
||||
contains_object = json_object_is_type(inner, json_type_object);
|
||||
if(filter){
|
||||
if(contains_object) {
|
||||
// printf("f\n");
|
||||
__dex_filter_array_object(inner, buf, context, filter);
|
||||
} else {
|
||||
printf("WTF!!!!!!!\n");
|
||||
}
|
||||
} else {
|
||||
if(contains_object) {
|
||||
// printf("g\n");
|
||||
__dex_magic_array_object(inner, buf, context);
|
||||
} else {
|
||||
// printf("h\n");
|
||||
__dex_simple_array_string(inner, buf, context);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case json_type_boolean:
|
||||
case json_type_double:
|
||||
case json_type_int:
|
||||
default:
|
||||
fprintf(stderr, "Invalid type in json\n");
|
||||
exit(1);
|
||||
}
|
||||
sprintbuf(buf, "</%s>\n", tag);
|
||||
}
|
||||
}
|
||||
|
||||
static void __dex_simple_single_string(struct json_object * json, struct printbuf * buf, contextPtr context){
|
||||
char* expr = myparse(astrdup(json_object_get_string(json)));
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"%s\" />\n", context->name, expr);
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"$%s\" />\n", __tag(context->name), context->name);
|
||||
sprintbuf(buf, "<xsl:value-of select=\"$%s\" />\n", context->name);
|
||||
}
|
||||
|
||||
static void __dex_filter_array_object(struct json_object * json, struct printbuf * buf, contextPtr context, char* filter){
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", filter);
|
||||
__dex_simple_single_object(json, buf, context);
|
||||
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
}
|
||||
|
||||
static void __dex_magic_array_object(struct json_object * json, struct printbuf * buf, contextPtr context){
|
||||
char* expr = myparse(astrdup(inner_key_of(json)));
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", expr);
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s__index\" select=\"count(set:intersection(following::*, .|.|.|%s))\" />", context->name, expr);
|
||||
|
||||
// <title><xsl:value-of select="key('page-key', $page_index)/h1" /></title>
|
||||
|
||||
__dex_simple_single_object(json, buf, context);
|
||||
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
}
|
||||
|
||||
static void __dex_simple_array_string(struct json_object * json, struct printbuf * buf, contextPtr context){
|
||||
char* expr = myparse(astrdup(json_object_get_string(json)));
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"%s\" />\n", context->name, expr);
|
||||
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"$%s\" />\n", __tag(context->name), context->name);
|
||||
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"$%s\"><dexter:group>\n", context->name);
|
||||
sprintbuf(buf, "<xsl:value-of select=\".\" />\n", context->name);
|
||||
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
|
||||
}
|
||||
|
||||
static char* full_expr(contextPtr context, char* expr){
|
||||
return expr_join(context->expr, expr);
|
||||
}
|
||||
|
||||
static char* expr_join(char* base, char* expr) {
|
||||
return astrcat3(base, " | ", expr);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue