📄 xinclude.c
字号:
* *
* XInclude Processing *
* *
************************************************************************/
/**
* xmlXIncludePreProcessNode:
* @ctxt: an XInclude context
* @node: an XInclude node
*
* Implement the XInclude preprocessing, currently just adding the element
* for further processing.
*
* Returns the result list or NULL in case of error
*/
static xmlNodePtr
xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
xmlXIncludeAddNode(ctxt, node);
return(0);
}
/**
* xmlXIncludeLoadNode:
* @ctxt: an XInclude context
* @nr: the node number
*
* Find and load the infoset replacement for the given node.
*
* Returns 0 if substitution succeeded, -1 if some processing failed
*/
static int
xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
xmlNodePtr cur;
xmlChar *href;
xmlChar *parse;
xmlChar *base;
xmlChar *oldBase;
xmlChar *URI;
int xml = 1; /* default Issue 64 */
int ret;
if (ctxt == NULL)
return(-1);
if ((nr < 0) || (nr >= ctxt->incNr))
return(-1);
cur = ctxt->incTab[nr]->ref;
if (cur == NULL)
return(-1);
/*
* read the attributes
*/
href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
if (href == NULL) {
href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
if (href == NULL)
return(-1);
}
parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
if (parse != NULL) {
if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
xml = 1;
else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
xml = 0;
else {
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_PARSE_VALUE,
"invalid value %s for 'parse'\n", parse);
if (href != NULL)
xmlFree(href);
if (parse != NULL)
xmlFree(parse);
return(-1);
}
}
/*
* compute the URI
*/
base = xmlNodeGetBase(ctxt->doc, cur);
if (base == NULL) {
URI = xmlBuildURI(href, ctxt->doc->URL);
} else {
URI = xmlBuildURI(href, base);
}
if (URI == NULL) {
xmlChar *escbase;
xmlChar *eschref;
/*
* Some escaping may be needed
*/
escbase = xmlURIEscape(base);
eschref = xmlURIEscape(href);
URI = xmlBuildURI(eschref, escbase);
if (escbase != NULL)
xmlFree(escbase);
if (eschref != NULL)
xmlFree(eschref);
}
if (URI == NULL) {
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
if (parse != NULL)
xmlFree(parse);
if (href != NULL)
xmlFree(href);
if (base != NULL)
xmlFree(base);
return(-1);
}
#ifdef DEBUG_XINCLUDE
xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
xml ? "xml": "text");
xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
#endif
/*
* Save the base for this include (saving the current one)
*/
oldBase = ctxt->base;
ctxt->base = base;
if (xml) {
ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
/* xmlXIncludeGetFragment(ctxt, cur, URI); */
} else {
ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
}
/*
* Restore the original base before checking for fallback
*/
ctxt->base = oldBase;
if (ret < 0) {
xmlNodePtr children;
/*
* Time to try a fallback if availble
*/
#ifdef DEBUG_XINCLUDE
xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
#endif
children = cur->children;
while (children != NULL) {
if ((children->type == XML_ELEMENT_NODE) &&
(children->ns != NULL) &&
(xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
(xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
ret = xmlXIncludeLoadFallback(ctxt, children, nr);
if (ret == 0)
break;
}
children = children->next;
}
}
if (ret < 0) {
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_NO_FALLBACK,
"could not load %s, and no fallback was found\n",
URI);
}
/*
* Cleanup
*/
if (URI != NULL)
xmlFree(URI);
if (parse != NULL)
xmlFree(parse);
if (href != NULL)
xmlFree(href);
if (base != NULL)
xmlFree(base);
return(0);
}
/**
* xmlXIncludeIncludeNode:
* @ctxt: an XInclude context
* @nr: the node number
*
* Inplement the infoset replacement for the given node
*
* Returns 0 if substitution succeeded, -1 if some processing failed
*/
static int
xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
xmlNodePtr cur, end, list, tmp;
if (ctxt == NULL)
return(-1);
if ((nr < 0) || (nr >= ctxt->incNr))
return(-1);
cur = ctxt->incTab[nr]->ref;
if (cur == NULL)
return(-1);
/*
* If we stored an XPointer a late computation may be needed
*/
if ((ctxt->incTab[nr]->inc == NULL) &&
(ctxt->incTab[nr]->xptr != NULL)) {
ctxt->incTab[nr]->inc =
xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
ctxt->incTab[nr]->xptr);
xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
ctxt->incTab[nr]->xptr = NULL;
}
list = ctxt->incTab[nr]->inc;
ctxt->incTab[nr]->inc = NULL;
/*
* Check against the risk of generating a multi-rooted document
*/
if ((cur->parent != NULL) &&
(cur->parent->type != XML_ELEMENT_NODE)) {
int nb_elem = 0;
tmp = list;
while (tmp != NULL) {
if (tmp->type == XML_ELEMENT_NODE)
nb_elem++;
tmp = tmp->next;
}
if (nb_elem > 1) {
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_MULTIPLE_ROOT,
"XInclude error: would result in multiple root nodes\n",
NULL);
return(-1);
}
}
if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
/*
* Add the list of nodes
*/
while (list != NULL) {
end = list;
list = list->next;
xmlAddPrevSibling(cur, end);
}
xmlUnlinkNode(cur);
xmlFreeNode(cur);
} else {
/*
* Change the current node as an XInclude start one, and add an
* XInclude end one
*/
cur->type = XML_XINCLUDE_START;
end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
if (end == NULL) {
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_BUILD_FAILED,
"failed to build node\n", NULL);
return(-1);
}
end->type = XML_XINCLUDE_END;
xmlAddNextSibling(cur, end);
/*
* Add the list of nodes
*/
while (list != NULL) {
cur = list;
list = list->next;
xmlAddPrevSibling(end, cur);
}
}
return(0);
}
/**
* xmlXIncludeTestNode:
* @ctxt: the XInclude processing context
* @node: an XInclude node
*
* test if the node is an XInclude node
*
* Returns 1 true, 0 otherwise
*/
static int
xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
if (node == NULL)
return(0);
if (node->type != XML_ELEMENT_NODE)
return(0);
if (node->ns == NULL)
return(0);
if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
(xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
if (ctxt->legacy == 0) {
#if 0 /* wait for the XML Core Working Group to get something stable ! */
xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
"Deprecated XInclude namespace found, use %s",
XINCLUDE_NS);
#endif
ctxt->legacy = 1;
}
}
if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
xmlNodePtr child = node->children;
int nb_fallback = 0;
while (child != NULL) {
if ((child->type == XML_ELEMENT_NODE) &&
(child->ns != NULL) &&
((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
(xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
xmlXIncludeErr(ctxt, node,
XML_XINCLUDE_INCLUDE_IN_INCLUDE,
"%s has an 'include' child\n",
XINCLUDE_NODE);
return(0);
}
if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
nb_fallback++;
}
}
child = child->next;
}
if (nb_fallback > 1) {
xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
"%s has multiple fallback children\n",
XINCLUDE_NODE);
return(0);
}
return(1);
}
if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
if ((node->parent == NULL) ||
(node->parent->type != XML_ELEMENT_NODE) ||
(node->parent->ns == NULL) ||
((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
(!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
(!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
xmlXIncludeErr(ctxt, node,
XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
"%s is not the child of an 'include'\n",
XINCLUDE_FALLBACK);
}
}
}
return(0);
}
/**
* xmlXIncludeDoProcess:
* @ctxt: the XInclude processing context
* @doc: an XML document
* @tree: the top of the tree to process
*
* Implement the XInclude substitution on the XML document @doc
*
* Returns 0 if no substitution were done, -1 if some processing failed
* or the number of substitutions done.
*/
static int
xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
xmlNodePtr cur;
int ret = 0;
int i;
if ((doc == NULL) || (tree == NULL))
return(-1);
if (ctxt == NULL)
return(-1);
if (doc->URL != NULL) {
ret = xmlXIncludeURLPush(ctxt, doc->URL);
if (ret < 0)
return(-1);
}
/*
* First phase: lookup the elements in the document
*/
cur = tree;
if (xmlXIncludeTestNode(ctxt, cur) == 1)
xmlXIncludePreProcessNode(ctxt, cur);
while ((cur != NULL) && (cur != tree->parent)) {
/* TODO: need to work on entities -> stack */
if ((cur->children != NULL) &&
(cur->children->type != XML_ENTITY_DECL) &&
(cur->children->type != XML_XINCLUDE_START) &&
(cur->children->type != XML_XINCLUDE_END)) {
cur = cur->children;
if (xmlXIncludeTestNode(ctxt, cur))
xmlXIncludePreProcessNode(ctxt, cur);
} else if (cur->next != NULL) {
cur = cur->next;
if (xmlXIncludeTestNode(ctxt, cur))
xmlXIncludePreProcessNode(ctxt, cur);
} else {
if (cur == tree)
break;
do {
cur = cur->parent;
if ((cur == NULL) || (cur == tree->parent))
break; /* do */
if (cur->next != NULL) {
cur = cur->next;
if (xmlXIncludeTestNode(ctxt, cur))
xmlXIncludePreProcessNode(ctxt, cur);
break; /* do */
}
} while (cur != NULL);
}
}
/*
* Second Phase : collect the infosets fragments
*/
for (i = ctxt->incBase;i < ctxt->incNr; i++) {
xmlXIncludeLoadNode(ctxt, i);
ret++;
}
/*
* Third phase: extend the original document infoset.
*
* Originally we bypassed the inclusion if there were any errors
* encountered on any of the XIncludes. A bug was raised (bug
* 132588) requesting that we output the XIncludes without error,
* so the check for inc!=NULL || xptr!=NULL was put in. This may
* give some other problems in the future, but for now it seems to
* work ok.
*
*/
for (i = ctxt->incBase;i < ctxt->incNr; i++) {
if ((ctxt->incTab[i]->inc != NULL) ||
(ctxt->incTab[i]->xptr != NULL) ||
(ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
xmlXIncludeIncludeNode(ctxt, i);
}
if (doc->URL != NULL)
xmlXIncludeURLPop(ctxt);
return(ret);
}
/**
* xmlXIncludeSetFlags:
* @ctxt: an XInclude processing context
* @flags: a set of xmlParserOption used for parsing XML includes
*
* Set the flags used for further processing of XML resources.
*
* Returns 0 in case of success and -1 in case of error.
*/
int
xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
if (ctxt == NULL)
return(-1);
ctxt->parseFlags = flags;
return(0);
}
/**
* xmlXIncludeProcessFlags:
* @doc: an XML document
* @flags: a set of xmlParserOption used for parsing XML includes
*
* Implement the XInclude substitution on the XML document @doc
*
* Returns 0 if no substitution were done, -1 if some processing failed
* or the number of substitutions done.
*/
int
xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
xmlXIncludeCtxtPtr ctxt;
xmlNodePtr tree
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -