#include "keys.h"
#include "pattern.h"
-/* #define DEBUG_PARSING */
+#define DEBUG_PATTERN
/*
* Types are private:
struct _xsltParserContext {
const xmlChar *cur; /* the current char being parsed */
const xmlChar *base; /* the full expression */
+ xmlDocPtr doc; /* the source document */
+ xmlNodePtr elem; /* the source element */
int error; /* error code */
xsltCompMatchPtr comp; /* the result */
};
case XSLT_OP_END:
return(1);
case XSLT_OP_ROOT:
- if ((node->type != XML_DOCUMENT_NODE) &&
- (node->type != XML_HTML_DOCUMENT_NODE))
- return(0);
- continue;
+ if ((node->type == XML_DOCUMENT_NODE) ||
+ (node->type == XML_HTML_DOCUMENT_NODE))
+ continue;
+ return(0);
case XSLT_OP_ELEM:
if (node->type != XML_ELEMENT_NODE)
return(0);
(node->type == XML_ELEMENT_NODE) &&
(node->parent != NULL)) {
- /* TODO: cache those informations ?!? */
+ /* TODO: cache those informations !!! */
xmlNodePtr siblings = node->parent->children;
while (siblings != NULL) {
void
xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
xmlChar *name = NULL;
+ xmlChar *prefix = NULL;
+ xmlChar *ncname = NULL;
+ xmlChar *URL = NULL;
SKIP_BLANKS;
if ((token == NULL) && (CUR == '@')) {
goto error;
}
}
+
+
SKIP_BLANKS;
if (CUR == '(') {
xsltCompileIdKeyPattern(ctxt, token, 0);
}
NEXT;
if (xmlStrEqual(token, (const xmlChar *) "child")) {
- /* TODO: handle namespace */
name = xsltScanName(ctxt);
if (name == NULL) {
xsltGenericError(xsltGenericErrorContext,
ctxt->error = 1;
goto error;
}
- PUSH(XSLT_OP_CHILD, name, NULL);
+ ncname = xmlSplitQName2(name, &prefix);
+ if (ncname != NULL) {
+ if (prefix != NULL) {
+ xmlNsPtr ns;
+
+ ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+ if (ns == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsl: pattern, no namespace bound to prefix %s\n",
+ prefix);
+ } else {
+ URL = xmlStrdup(ns->href);
+ }
+ xmlFree(prefix);
+ }
+ xmlFree(name);
+ name = ncname;
+ }
+ PUSH(XSLT_OP_CHILD, name, URL);
} else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
- /* TODO: handle namespace */
name = xsltScanName(ctxt);
if (name == NULL) {
xsltGenericError(xsltGenericErrorContext,
ctxt->error = 1;
goto error;
}
- PUSH(XSLT_OP_ATTR, name, NULL);
+ ncname = xmlSplitQName2(name, &prefix);
+ if (ncname != NULL) {
+ if (prefix != NULL) {
+ xmlNsPtr ns;
+
+ ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+ if (ns == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsl: pattern, no namespace bound to prefix %s\n",
+ prefix);
+ } else {
+ URL = xmlStrdup(ns->href);
+ }
+ xmlFree(prefix);
+ }
+ xmlFree(name);
+ name = ncname;
+ }
+ PUSH(XSLT_OP_ATTR, name, URL);
} else {
xsltGenericError(xsltGenericErrorContext,
"xsltCompileStepPattern : 'child' or 'attribute' expected\n");
NEXT;
PUSH(XSLT_OP_ALL, token, NULL);
} else {
- /* TODO: handle namespace */
- PUSH(XSLT_OP_ELEM, token, NULL);
+ ncname = xmlSplitQName2(token, &prefix);
+ if (ncname != NULL) {
+ if (prefix != NULL) {
+ xmlNsPtr ns;
+
+ ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+ if (ns == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsl: pattern, no namespace bound to prefix %s\n",
+ prefix);
+ } else {
+ URL = xmlStrdup(ns->href);
+ }
+ xmlFree(prefix);
+ }
+ xmlFree(token);
+ token = ncname;
+ }
+ PUSH(XSLT_OP_ELEM, token, URL);
}
parse_predicate:
SKIP_BLANKS;
/**
* xsltCompilePattern:
* @pattern an XSLT pattern
+ * @doc: the containing document
+ * @node: the containing element
*
* Compile the XSLT pattern and generates a list of precompiled form suitable
* for fast matching.
*/
xsltCompMatchPtr
-xsltCompilePattern(const xmlChar *pattern) {
+xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc, xmlNodePtr node) {
xsltParserContextPtr ctxt = NULL;
xsltCompMatchPtr element, first = NULL, previous = NULL;
int current, start, end;
return(NULL);
}
-#ifdef DEBUG_PARSING
+#ifdef DEBUG_PATTERN
xsltGenericDebug(xsltGenericDebugContext,
"xsltCompilePattern : parsing '%s'\n", pattern);
#endif
ctxt = xsltNewParserContext();
if (ctxt == NULL)
return(NULL);
+ ctxt->doc = doc;
+ ctxt->elem = node;
current = end = 0;
while (pattern[current] != 0) {
start = current;
(element->steps[0].value != NULL) &&
(element->steps[1].op == XSLT_OP_END)) {
element->priority = 0;
+ } else if ((element->steps[0].op == XSLT_OP_ROOT) &&
+ (element->steps[1].op == XSLT_OP_END)) {
+ element->priority = 0;
} else if ((element->steps[0].op == XSLT_OP_PI) &&
(element->steps[0].value != NULL) &&
(element->steps[1].op == XSLT_OP_END)) {
if ((style == NULL) || (cur == NULL) || (cur->match == NULL))
return(-1);
- pat = xsltCompilePattern(cur->match);
+ pat = xsltCompilePattern(cur->match, style->doc, cur->elem);
while (pat) {
next = pat->next;
pat->next = NULL;
pat->mode = xmlStrdup(mode);
if (modeURI != NULL)
pat->modeURI = xmlStrdup(modeURI);
- if (pat->priority != XSLT_PAT_NO_PRIORITY)
+ if (cur->priority == XSLT_PAT_NO_PRIORITY)
cur->priority = pat->priority;
else
pat->priority = cur->priority;
xsltFreeCompMatch(pat);
return(-1);
}
-#ifdef DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAddTemplate: created template hash\n");
-#endif
xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
-#ifdef DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAddTemplate: added new hash %s\n", name);
-#endif
} else {
list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
name, mode, modeURI);
if (list == NULL) {
xmlHashAddEntry3(style->templatesHash, name,
mode, modeURI, pat);
-#ifdef DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAddTemplate: added new hash %s\n", name);
-#endif
} else {
/*
* Note '<=' since one must choose among the matching
pat->next = list;
xmlHashUpdateEntry3(style->templatesHash, name,
mode, modeURI, pat, NULL);
-#ifdef DEBUG_PARSING
- xsltGenericDebug(xsltGenericDebugContext,
- "xsltAddTemplate: added head hash for %s\n", name);
-#endif
} else {
while (list->next != NULL) {
if (list->next->priority <= pat->priority)
xsltFreeCompMatch(pat);
return(-1);
}
+#ifdef DEBUG_PATTERN
+ xsltGenericDebug(xsltGenericDebugContext,
+ "added pattern : '%s' priority %f\n",
+ pat->template->match, pat->priority);
+#endif
+
pat = next;
}
return(0);
list = list->next;
}
}
-
if (ret != NULL)
return(ret);
xsltFreeCompMatchList(style->commentMatch);
}
+#if 0
/**
* xsltMatchPattern
* @node: a node in the source tree
}
return match;
}
-
+#endif
xsltFreeStackElemList(sheet->variables);
if (sheet->stripSpaces != NULL)
xmlHashFree(sheet->stripSpaces, NULL);
+ if (sheet->nsHash != NULL)
+ xmlHashFree(sheet->nsHash, NULL);
if (sheet->method != NULL) xmlFree(sheet->method);
if (sheet->methodURI != NULL) xmlFree(sheet->methodURI);
}
/**
+ * xsltGatherNamespaces:
+ * @style: the XSLT stylesheet
+ *
+ * Browse the stylesheet and buit the namspace hash table which
+ * will be used for XPath interpretation. If needed do a bit of normalization
+ */
+
+void
+xsltGatherNamespaces(xsltStylesheetPtr style) {
+ xmlNodePtr cur;
+ const xmlChar *URI;
+
+ /*
+ * TODO: basically if the stylesheet uses the same prefix for different
+ * patterns, well they may be in problem, hopefully they will get
+ * a warning first.
+ */
+ cur = xmlDocGetRootElement(style->doc);
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ xmlNsPtr ns = cur->nsDef;
+ while (ns != NULL) {
+ if (ns->prefix != NULL) {
+ if (style->nsHash == NULL) {
+ style->nsHash = xmlHashCreate(10);
+ if (style->nsHash == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltGatherNamespaces: failed to create hash table\n");
+ return;
+ }
+ }
+ URI = xmlHashLookup(style->nsHash, ns->prefix);
+ if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
+ xsltGenericError(xsltGenericErrorContext,
+ "Namespaces prefix %s used for multiple namespaces\n");
+ } else if (URI == NULL) {
+ xmlHashUpdateEntry(style->nsHash, ns->prefix,
+ (void *) ns->href, (xmlHashDeallocator)xmlFree);
+
+#ifdef DEBUG_PARSING
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
+#endif
+ }
+ }
+ ns = ns->next;
+ }
+ }
+
+ /*
+ * Skip to next node
+ */
+ if (cur->children != NULL) {
+ if (cur->children->type != XML_ENTITY_DECL) {
+ cur = cur->children;
+ continue;
+ }
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ continue;
+ }
+
+ do {
+ cur = cur->parent;
+ if (cur == NULL)
+ break;
+ if (cur == (xmlNodePtr) style->doc) {
+ cur = NULL;
+ break;
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+ } while (cur != NULL);
+ }
+}
+
+/**
* xsltParseTemplateContent:
* @style: the XSLT stylesheet
* @ret: the "template" structure
* For stylesheets, the set of whitespace-preserving
* element names consists of just xsl:text.
*/
+ ret->elem = template;
cur = template->children;
delete = NULL;
while (cur != NULL) {
return(NULL);
ret->doc = doc;
+ xsltGatherNamespaces(ret);
xsltParseStylesheetProcess(ret, doc);
return(ret);