From fe557f63a66bc0b745f6fd2beb698fcbb5568ab8 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Sun, 28 Jan 2001 16:27:44 +0000 Subject: [PATCH] Work done on namespace support: - FEATURES TODO: updates - libxslt/namespaces.[ch] libxslt/templates.c libxslt/transform.c libxslt/xslt.c libxslt/xsltInternals.h: added support for namespace aliases and cleaned up the overall namespace related code. This materialize as a new module. Daniel --- ChangeLog | 8 ++ FEATURES | 10 +-- TODO | 8 +- libxslt/Makefile.am | 2 + libxslt/namespaces.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++ libxslt/namespaces.h | 32 ++++++++ libxslt/templates.c | 19 +---- libxslt/transform.c | 58 +++++--------- libxslt/xslt.c | 3 +- libxslt/xsltInternals.h | 5 ++ 10 files changed, 284 insertions(+), 65 deletions(-) create mode 100644 libxslt/namespaces.c create mode 100644 libxslt/namespaces.h diff --git a/ChangeLog b/ChangeLog index cd2eefd..ea0627e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Jan 28 17:25:35 CET 2001 Daniel Veillard + + * FEATURES TODO: updates + * libxslt/namespaces.[ch] libxslt/templates.c libxslt/transform.c + libxslt/xslt.c libxslt/xsltInternals.h: added support for + namespace aliases and cleaned up the overall namespace related + code. This materialize as a new module. + Sun Jan 28 08:41:10 CET 2001 Daniel Veillard * configure.in libxslt.spec.in: changes needed for libxml2-devel diff --git a/FEATURES b/FEATURES index 16e2efa..08e00c8 100644 --- a/FEATURES +++ b/FEATURES @@ -45,9 +45,9 @@ YES name = qname YES priority = number NO mode = qname -NO xsl:namespace-alias -NO stylesheet-prefix = prefix | "#default" -NO result-prefix = prefix | "#default" +YES xsl:namespace-alias +YES stylesheet-prefix = prefix | "#default" +YES result-prefix = prefix | "#default" NO xsl:attribute-set NO name = qname @@ -99,7 +99,7 @@ NO use-attribute-sets = qnames YES xsl:attribute YES name = { qname } -YES namespace = { uri-reference } +NO namespace = { uri-reference } YES xsl:text YES disable-output-escaping = "yes" | "no" @@ -193,7 +193,7 @@ YES Built-in Template Rules YES match="*|/" YES match="text()|@*" YES match="processing-instruction()|comment()" -NO Namespace +YES Namespace NO Mode NO Extension Elements diff --git a/TODO b/TODO index 47d246b..2253637 100644 --- a/TODO +++ b/TODO @@ -5,9 +5,6 @@ ******** Doc: - - put a page at http://xmlsoft.org/XSLT/ - - generate/transform the DocBook to HTML - - add HTML to package - manpage and doc for xsltproc Design: @@ -92,3 +89,8 @@ Pattern tester: -> also put fast lookup for "text()", "comment()", "node()" based patterns lists. => done + +Doc: + - put a page at http://xmlsoft.org/XSLT/ + - generate/transform the DocBook to HTML + - add HTML to package diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am index 6036591..f582bf1 100644 --- a/libxslt/Makefile.am +++ b/libxslt/Makefile.am @@ -12,6 +12,7 @@ xsltinc_HEADERS = \ templates.h \ variables.h \ functions.h \ + namespaces.h \ transform.h \ xsltInternals.h @@ -22,6 +23,7 @@ libxslt_la_SOURCES = \ templates.c \ variables.c \ functions.c \ + namespaces.c \ transform.c diff --git a/libxslt/namespaces.c b/libxslt/namespaces.c new file mode 100644 index 0000000..9842453 --- /dev/null +++ b/libxslt/namespaces.c @@ -0,0 +1,204 @@ +/* + * namespaces.c: Implementation of the XSLT namespaces handling + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#include "xsltconfig.h" + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_MATH_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_IEEEFP_H +#include +#endif +#ifdef HAVE_NAN_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif + +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "namespaces.h" + + + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltNamespaceAlias: + * @style: the XSLT stylesheet + * @node: the xsl:namespace-alias node + * + * Read the stylesheet-prefix and result-prefix attributes, register + * them as well as the corresponding namespace. + */ +void +xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) { + xmlChar *sprefix; + xmlNsPtr sNs; + xmlChar *rprefix; + xmlNsPtr rNs; + + sprefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", + XSLT_NAMESPACE); + if (sprefix == NULL) { + xsltGenericError(xsltGenericErrorContext, + "namespace-alias: stylesheet-prefix attribute missing\n"); + return; + } + rprefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", + XSLT_NAMESPACE); + if (rprefix == NULL) { + xsltGenericError(xsltGenericErrorContext, + "namespace-alias: result-prefix attribute missing\n"); + goto error; + } + if (xmlStrEqual(sprefix, (const xmlChar *)"#default")) { + sNs = xmlSearchNs(node->doc, node, NULL); + } else { + sNs = xmlSearchNs(node->doc, node, sprefix); + } + if ((sNs == NULL) || (sNs->href == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "namespace-alias: prefix %s not bound to any namespace\n", + sprefix); + goto error; + } + if (xmlStrEqual(rprefix, (const xmlChar *)"#default")) { + rNs = xmlSearchNs(node->doc, node, NULL); + } else { + rNs = xmlSearchNs(node->doc, node, rprefix); + } + if ((rNs == NULL) || (rNs->href == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "namespace-alias: prefix %s not bound to any namespace\n", + rprefix); + goto error; + } + if (style->nsAliases == NULL) + style->nsAliases = xmlHashCreate(10); + if (style->nsAliases == NULL) { + xsltGenericError(xsltGenericErrorContext, + "namespace-alias: cannot create hash table\n"); + goto error; + } + xmlHashAddEntry((xmlHashTablePtr) style->nsAliases, + sNs->href, (void *) rNs->href); + +error: + if (sprefix != NULL) + xmlFree(sprefix); + if (rprefix != NULL) + xmlFree(rprefix); +} + +/** + * xsltGetNamespace: + * @ctxt: a transformation context + * @cur: the input node + * @ns: the namespace + * @out: the output node (or its parent) + * + * Find the right namespace value for this prefix, if needed create + * and add a new namespace decalaration on the node + * Handle namespace aliases + * + * Returns the namespace node to use or NULL + */ +xmlNsPtr +xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns, + xmlNodePtr out) { + xmlNsPtr ret; + const xmlChar *URI; + + if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL)) + return(NULL); + if ((out->type == XML_ELEMENT_NODE) && (out->ns != NULL) && + ((out->ns->href != NULL) && (ns->href != NULL) && + (xmlStrEqual(out->ns->href, ns->href)))) { + return(out->ns); + } + + /* TODO apply cascading */ + if (ctxt->style->nsAliases != NULL) { + URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases, ns->href); + if (URI == NULL) + URI = ns->href; + } else + URI = ns->href; + + ret = xmlSearchNsByHref(out->doc, out, URI); + if (ret == NULL) { + if (out->type == XML_ELEMENT_NODE) + ret = xmlNewNs(out, ns->href, ns->prefix); + } + return(ret); +} + +/** + * xsltCopyNamespaceList: + * @ctxt: a transformation context + * @node: the target node + * @cur: the first namespace + * + * Do a copy of an namespace list. If @node is non-NULL the + * new namespaces are added automatically. This handles namespaces + * aliases + * + * Returns: a new xmlNsPtr, or NULL in case of error. + */ +xmlNsPtr +xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNsPtr cur) { + xmlNsPtr ret = NULL; + xmlNsPtr p = NULL,q; + const xmlChar *URI; + + while (cur != NULL) { + if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) { + /* TODO apply cascading */ + URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases, + cur->href); + if (URI != NULL) { + q = xmlNewNs(node, URI, cur->prefix); + } else { + q = xmlNewNs(node, cur->href, cur->prefix); + } + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + p = q; + } + } + cur = cur->next; + } + return(ret); +} + diff --git a/libxslt/namespaces.h b/libxslt/namespaces.h new file mode 100644 index 0000000..14c2f4d --- /dev/null +++ b/libxslt/namespaces.h @@ -0,0 +1,32 @@ +/* + * namespaces.h: interface for the XSLT namespace handling + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#ifndef __XML_XSLT_NAMESPACES_H__ +#define __XML_XSLT_NAMESPACES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void xsltNamespaceAlias (xsltStylesheetPtr style, + xmlNodePtr node); +xmlNsPtr xsltGetNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + xmlNsPtr ns, + xmlNodePtr out); +xmlNsPtr xsltCopyNamespaceList (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNsPtr cur); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_NAMESPACES_H__ */ + diff --git a/libxslt/templates.c b/libxslt/templates.c index ebc0b4d..66d6e40 100644 --- a/libxslt/templates.c +++ b/libxslt/templates.c @@ -25,6 +25,7 @@ #include "functions.h" #include "templates.h" #include "transform.h" +#include "namespaces.h" #define DEBUG_TEMPLATES @@ -264,23 +265,7 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, if (ret == NULL) return(NULL); ret->parent = target; - if ((cur->ns != NULL) && (target != NULL)) { - if ((target != NULL) && (target->ns != NULL) && - (xmlStrEqual(target->ns->href, cur->ns->href))) { - ret->ns = target->ns; - } else { - xmlNsPtr ns; - - ns = xmlSearchNsByHref(ctxt->output, target, cur->ns->href); - if (ns != NULL) { - ret->ns = ns; - } else { - ns = xmlNewNs(target, cur->ns->href, cur->ns->prefix); - ret->ns = ns; - } - } - } else - ret->ns = NULL; + ret->ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target); if (cur->children != NULL) { xmlChar *in = xmlNodeListGetString(ctxt->doc, cur->children, 1); diff --git a/libxslt/transform.c b/libxslt/transform.c index 81eb3c9..171e45b 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -30,6 +30,7 @@ #include "pattern.h" #include "transform.h" #include "variables.h" +#include "namespaces.h" #include "templates.h" #define DEBUG_PROCESS @@ -349,12 +350,6 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, "xslt:attribute : node has already children\n"); return; } - prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace"); - if (prop != NULL) { - TODO /* xsl:attribute namespace */ - xmlFree(prop); - return; - } prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name"); if (prop == NULL) { xsltGenericError(xsltGenericErrorContext, @@ -373,13 +368,23 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, "xslt:attribute : xmlns forbidden\n"); goto error; } - if ((prefix != NULL) && (ns == NULL)) { - ns = xmlSearchNs(ctxt->insert->doc, ctxt->insert, prefix); - if (ns == NULL) { - xsltGenericError(xsltGenericErrorContext, - "no namespace bound to prefix %s\n", prefix); + prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace"); + if (prop != NULL) { + TODO /* xsl:attribute namespace */ + xmlFree(prop); + return; + } else { + if (prefix != NULL) { + ns = xmlSearchNs(inst->doc, inst, prefix); + if (ns == NULL) { + xsltGenericError(xsltGenericErrorContext, + "no namespace bound to prefix %s\n", prefix); + } else { + ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert); + } } } + value = xsltEvalTemplateString(ctxt, node, inst); if (value == NULL) { @@ -528,34 +533,9 @@ xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node, * Add namespaces as they are needed */ if (node->nsDef != NULL) - copy->nsDef = xmlCopyNamespaceList(node->nsDef); + xsltCopyNamespaceList(ctxt, copy, node->nsDef); if (node->ns != NULL) { - /* - * optimization, if the namespace is already the - * on on the parent node, reuse it directly - * - * TODO: check possible mess with xmlCopyNamespaceList - */ - if ((insert->type == XML_ELEMENT_NODE) && - (insert->ns != NULL) && - (xmlStrEqual(insert->ns->href, node->ns->href))) { - copy->ns = insert->ns; - } else { - xmlNsPtr ns; - - /* - * Look in the output tree if the namespace is - * already in scope. - */ - ns = xmlSearchNsByHref(ctxt->output, copy, - node->ns->href); - if (ns != NULL) - copy->ns = ns; - else { - ns = xmlNewNs(copy, node->ns->href, - node->ns->prefix); - } - } + copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert); } } else { xsltGenericError(xsltGenericErrorContext, @@ -697,7 +677,7 @@ xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlChar *prefix = NULL; xmlNsPtr ns = NULL; xsltTemplatePtr template; - xmlNodePtr cur; + xmlNodePtr cur = NULL; int has_param = 0; diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 4d4898c..66a838b 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -24,6 +24,7 @@ #include "xsltInternals.h" #include "pattern.h" #include "variables.h" +#include "namespaces.h" #include "xsltutils.h" #define DEBUG_PARSING @@ -784,7 +785,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { #endif xsltParseStylesheetTemplate(style, cur); } else if (IS_XSLT_NAME(cur, "namespace-alias")) { - TODO /* Handle namespace-alias */ + xsltNamespaceAlias(style, cur); } else { xsltGenericError(xsltGenericErrorContext, "xsltParseStylesheetTop: ignoring unknown %s element\n", diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 7250e7c..9056dc5 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -102,6 +102,11 @@ struct _xsltStylesheet { void *commentMatch; /* template based on comment() */ /* + * Namespace aliases + */ + xmlHashTablePtr nsAliases; /* the namespace alias hash tables */ + + /* * Output related stuff. */ xmlChar *method; /* the output method */ -- 2.7.4