templates.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /*
  2. * templates.c: Implementation of the template processing
  3. *
  4. * Reference:
  5. * http://www.w3.org/TR/1999/REC-xslt-19991116
  6. *
  7. * See Copyright for the status of this software.
  8. *
  9. * daniel@veillard.com
  10. */
  11. #define IN_LIBXSLT
  12. #include "libxslt.h"
  13. #include <string.h>
  14. #include <libxml/xmlmemory.h>
  15. #include <libxml/globals.h>
  16. #include <libxml/xmlerror.h>
  17. #include <libxml/tree.h>
  18. #include <libxml/dict.h>
  19. #include <libxml/xpathInternals.h>
  20. #include <libxml/parserInternals.h>
  21. #include "xslt.h"
  22. #include "xsltInternals.h"
  23. #include "xsltutils.h"
  24. #include "variables.h"
  25. #include "functions.h"
  26. #include "templates.h"
  27. #include "transform.h"
  28. #include "namespaces.h"
  29. #include "attributes.h"
  30. #ifdef WITH_XSLT_DEBUG
  31. #define WITH_XSLT_DEBUG_TEMPLATES
  32. #endif
  33. /************************************************************************
  34. * *
  35. * Module interfaces *
  36. * *
  37. ************************************************************************/
  38. /**
  39. * xsltEvalXPathPredicate:
  40. * @ctxt: the XSLT transformation context
  41. * @comp: the XPath compiled expression
  42. * @nsList: the namespaces in scope
  43. * @nsNr: the number of namespaces in scope
  44. *
  45. * Process the expression using XPath and evaluate the result as
  46. * an XPath predicate
  47. *
  48. * Returns 1 is the predicate was true, 0 otherwise
  49. */
  50. int
  51. xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
  52. xmlNsPtr *nsList, int nsNr) {
  53. int ret;
  54. xmlXPathObjectPtr res;
  55. int oldNsNr;
  56. xmlNsPtr *oldNamespaces;
  57. xmlNodePtr oldInst;
  58. int oldProximityPosition, oldContextSize;
  59. if ((ctxt == NULL) || (ctxt->inst == NULL)) {
  60. xsltTransformError(ctxt, NULL, NULL,
  61. "xsltEvalXPathPredicate: No context or instruction\n");
  62. return(0);
  63. }
  64. oldContextSize = ctxt->xpathCtxt->contextSize;
  65. oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
  66. oldNsNr = ctxt->xpathCtxt->nsNr;
  67. oldNamespaces = ctxt->xpathCtxt->namespaces;
  68. oldInst = ctxt->inst;
  69. ctxt->xpathCtxt->node = ctxt->node;
  70. ctxt->xpathCtxt->namespaces = nsList;
  71. ctxt->xpathCtxt->nsNr = nsNr;
  72. res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
  73. if (res != NULL) {
  74. ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);
  75. xmlXPathFreeObject(res);
  76. #ifdef WITH_XSLT_DEBUG_TEMPLATES
  77. XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  78. "xsltEvalXPathPredicate: returns %d\n", ret));
  79. #endif
  80. } else {
  81. #ifdef WITH_XSLT_DEBUG_TEMPLATES
  82. XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  83. "xsltEvalXPathPredicate: failed\n"));
  84. #endif
  85. ctxt->state = XSLT_STATE_STOPPED;
  86. ret = 0;
  87. }
  88. ctxt->xpathCtxt->nsNr = oldNsNr;
  89. ctxt->xpathCtxt->namespaces = oldNamespaces;
  90. ctxt->inst = oldInst;
  91. ctxt->xpathCtxt->contextSize = oldContextSize;
  92. ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
  93. return(ret);
  94. }
  95. /**
  96. * xsltEvalXPathStringNs:
  97. * @ctxt: the XSLT transformation context
  98. * @comp: the compiled XPath expression
  99. * @nsNr: the number of namespaces in the list
  100. * @nsList: the list of in-scope namespaces to use
  101. *
  102. * Process the expression using XPath, allowing to pass a namespace mapping
  103. * context and get a string
  104. *
  105. * Returns the computed string value or NULL, must be deallocated by the
  106. * caller.
  107. */
  108. xmlChar *
  109. xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
  110. int nsNr, xmlNsPtr *nsList) {
  111. xmlChar *ret = NULL;
  112. xmlXPathObjectPtr res;
  113. xmlNodePtr oldInst;
  114. xmlNodePtr oldNode;
  115. int oldPos, oldSize;
  116. int oldNsNr;
  117. xmlNsPtr *oldNamespaces;
  118. if ((ctxt == NULL) || (ctxt->inst == NULL)) {
  119. xsltTransformError(ctxt, NULL, NULL,
  120. "xsltEvalXPathStringNs: No context or instruction\n");
  121. return(0);
  122. }
  123. oldInst = ctxt->inst;
  124. oldNode = ctxt->node;
  125. oldPos = ctxt->xpathCtxt->proximityPosition;
  126. oldSize = ctxt->xpathCtxt->contextSize;
  127. oldNsNr = ctxt->xpathCtxt->nsNr;
  128. oldNamespaces = ctxt->xpathCtxt->namespaces;
  129. ctxt->xpathCtxt->node = ctxt->node;
  130. /* TODO: do we need to propagate the namespaces here ? */
  131. ctxt->xpathCtxt->namespaces = nsList;
  132. ctxt->xpathCtxt->nsNr = nsNr;
  133. res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
  134. if (res != NULL) {
  135. if (res->type != XPATH_STRING)
  136. res = xmlXPathConvertString(res);
  137. if (res->type == XPATH_STRING) {
  138. ret = res->stringval;
  139. res->stringval = NULL;
  140. } else {
  141. xsltTransformError(ctxt, NULL, NULL,
  142. "xpath : string() function didn't return a String\n");
  143. }
  144. xmlXPathFreeObject(res);
  145. } else {
  146. ctxt->state = XSLT_STATE_STOPPED;
  147. }
  148. #ifdef WITH_XSLT_DEBUG_TEMPLATES
  149. XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  150. "xsltEvalXPathString: returns %s\n", ret));
  151. #endif
  152. ctxt->inst = oldInst;
  153. ctxt->node = oldNode;
  154. ctxt->xpathCtxt->contextSize = oldSize;
  155. ctxt->xpathCtxt->proximityPosition = oldPos;
  156. ctxt->xpathCtxt->nsNr = oldNsNr;
  157. ctxt->xpathCtxt->namespaces = oldNamespaces;
  158. return(ret);
  159. }
  160. /**
  161. * xsltEvalXPathString:
  162. * @ctxt: the XSLT transformation context
  163. * @comp: the compiled XPath expression
  164. *
  165. * Process the expression using XPath and get a string
  166. *
  167. * Returns the computed string value or NULL, must be deallocated by the
  168. * caller.
  169. */
  170. xmlChar *
  171. xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
  172. return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL));
  173. }
  174. /**
  175. * xsltEvalTemplateString:
  176. * @ctxt: the XSLT transformation context
  177. * @contextNode: the current node in the source tree
  178. * @inst: the XSLT instruction (xsl:comment, xsl:processing-instruction)
  179. *
  180. * Processes the sequence constructor of the given instruction on
  181. * @contextNode and converts the resulting tree to a string.
  182. * This is needed by e.g. xsl:comment and xsl:processing-instruction.
  183. *
  184. * Returns the computed string value or NULL; it's up to the caller to
  185. * free the result.
  186. */
  187. xmlChar *
  188. xsltEvalTemplateString(xsltTransformContextPtr ctxt,
  189. xmlNodePtr contextNode,
  190. xmlNodePtr inst)
  191. {
  192. xmlNodePtr oldInsert, insert = NULL;
  193. xmlChar *ret;
  194. const xmlChar *oldLastText;
  195. int oldLastTextSize, oldLastTextUse;
  196. if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) ||
  197. (inst->type != XML_ELEMENT_NODE))
  198. return(NULL);
  199. if (inst->children == NULL)
  200. return(NULL);
  201. /*
  202. * This creates a temporary element-node to add the resulting
  203. * text content to.
  204. * OPTIMIZE TODO: Keep such an element-node in the transformation
  205. * context to avoid creating it every time.
  206. */
  207. insert = xmlNewDocNode(ctxt->output, NULL,
  208. (const xmlChar *)"fake", NULL);
  209. if (insert == NULL) {
  210. xsltTransformError(ctxt, NULL, contextNode,
  211. "Failed to create temporary node\n");
  212. return(NULL);
  213. }
  214. oldInsert = ctxt->insert;
  215. ctxt->insert = insert;
  216. oldLastText = ctxt->lasttext;
  217. oldLastTextSize = ctxt->lasttsize;
  218. oldLastTextUse = ctxt->lasttuse;
  219. /*
  220. * OPTIMIZE TODO: if inst->children consists only of text-nodes.
  221. */
  222. xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);
  223. ctxt->insert = oldInsert;
  224. ctxt->lasttext = oldLastText;
  225. ctxt->lasttsize = oldLastTextSize;
  226. ctxt->lasttuse = oldLastTextUse;
  227. ret = xmlNodeGetContent(insert);
  228. if (insert != NULL)
  229. xmlFreeNode(insert);
  230. return(ret);
  231. }
  232. /**
  233. * xsltAttrTemplateValueProcessNode:
  234. * @ctxt: the XSLT transformation context
  235. * @str: the attribute template node value
  236. * @inst: the instruction (or LRE) in the stylesheet holding the
  237. * attribute with an AVT
  238. *
  239. * Process the given string, allowing to pass a namespace mapping
  240. * context and return the new string value.
  241. *
  242. * Called by:
  243. * - xsltAttrTemplateValueProcess() (templates.c)
  244. * - xsltEvalAttrValueTemplate() (templates.c)
  245. *
  246. * QUESTION: Why is this function public? It is not used outside
  247. * of templates.c.
  248. *
  249. * Returns the computed string value or NULL, must be deallocated by the
  250. * caller.
  251. */
  252. xmlChar *
  253. xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
  254. const xmlChar *str, xmlNodePtr inst)
  255. {
  256. xmlChar *ret = NULL;
  257. const xmlChar *cur;
  258. xmlChar *expr, *val;
  259. xmlNsPtr *nsList = NULL;
  260. int nsNr = 0;
  261. if (str == NULL) return(NULL);
  262. if (*str == 0)
  263. return(xmlStrndup((xmlChar *)"", 0));
  264. cur = str;
  265. while (*cur != 0) {
  266. if (*cur == '{') {
  267. if (*(cur+1) == '{') { /* escaped '{' */
  268. cur++;
  269. ret = xmlStrncat(ret, str, cur - str);
  270. cur++;
  271. str = cur;
  272. continue;
  273. }
  274. ret = xmlStrncat(ret, str, cur - str);
  275. str = cur;
  276. cur++;
  277. while ((*cur != 0) && (*cur != '}')) {
  278. /* Need to check for literal (bug539741) */
  279. if ((*cur == '\'') || (*cur == '"')) {
  280. char delim = *(cur++);
  281. while ((*cur != 0) && (*cur != delim))
  282. cur++;
  283. if (*cur != 0)
  284. cur++; /* skip the ending delimiter */
  285. } else
  286. cur++;
  287. }
  288. if (*cur == 0) {
  289. xsltTransformError(ctxt, NULL, inst,
  290. "xsltAttrTemplateValueProcessNode: unmatched '{'\n");
  291. ret = xmlStrncat(ret, str, cur - str);
  292. goto exit;
  293. }
  294. str++;
  295. expr = xmlStrndup(str, cur - str);
  296. if (expr == NULL)
  297. goto exit;
  298. else if (*expr == '{') {
  299. ret = xmlStrcat(ret, expr);
  300. xmlFree(expr);
  301. } else {
  302. xmlXPathCompExprPtr comp;
  303. /*
  304. * TODO: keep precompiled form around
  305. */
  306. if ((nsList == NULL) && (inst != NULL)) {
  307. int i = 0;
  308. nsList = xmlGetNsList(inst->doc, inst);
  309. if (nsList != NULL) {
  310. while (nsList[i] != NULL)
  311. i++;
  312. nsNr = i;
  313. }
  314. }
  315. comp = xmlXPathCtxtCompile(ctxt->xpathCtxt, expr);
  316. val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList);
  317. xmlXPathFreeCompExpr(comp);
  318. xmlFree(expr);
  319. if (val != NULL) {
  320. ret = xmlStrcat(ret, val);
  321. xmlFree(val);
  322. }
  323. }
  324. cur++;
  325. str = cur;
  326. } else if (*cur == '}') {
  327. cur++;
  328. if (*cur == '}') { /* escaped '}' */
  329. ret = xmlStrncat(ret, str, cur - str);
  330. cur++;
  331. str = cur;
  332. continue;
  333. } else {
  334. xsltTransformError(ctxt, NULL, inst,
  335. "xsltAttrTemplateValueProcessNode: unmatched '}'\n");
  336. }
  337. } else
  338. cur++;
  339. }
  340. if (cur != str) {
  341. ret = xmlStrncat(ret, str, cur - str);
  342. }
  343. exit:
  344. if (nsList != NULL)
  345. xmlFree(nsList);
  346. return(ret);
  347. }
  348. /**
  349. * xsltAttrTemplateValueProcess:
  350. * @ctxt: the XSLT transformation context
  351. * @str: the attribute template node value
  352. *
  353. * Process the given node and return the new string value.
  354. *
  355. * Returns the computed string value or NULL, must be deallocated by the
  356. * caller.
  357. */
  358. xmlChar *
  359. xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
  360. return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL));
  361. }
  362. /**
  363. * xsltEvalAttrValueTemplate:
  364. * @ctxt: the XSLT transformation context
  365. * @inst: the instruction (or LRE) in the stylesheet holding the
  366. * attribute with an AVT
  367. * @name: the attribute QName
  368. * @ns: the attribute namespace URI
  369. *
  370. * Evaluate a attribute value template, i.e. the attribute value can
  371. * contain expressions contained in curly braces ({}) and those are
  372. * substituted by they computed value.
  373. *
  374. * Returns the computed string value or NULL, must be deallocated by the
  375. * caller.
  376. */
  377. xmlChar *
  378. xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
  379. const xmlChar *name, const xmlChar *ns)
  380. {
  381. xmlChar *ret;
  382. xmlChar *expr;
  383. if ((ctxt == NULL) || (inst == NULL) || (name == NULL) ||
  384. (inst->type != XML_ELEMENT_NODE))
  385. return(NULL);
  386. expr = xsltGetNsProp(inst, name, ns);
  387. if (expr == NULL)
  388. return(NULL);
  389. /*
  390. * TODO: though now {} is detected ahead, it would still be good to
  391. * optimize both functions to keep the splitted value if the
  392. * attribute content and the XPath precompiled expressions around
  393. */
  394. ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst);
  395. #ifdef WITH_XSLT_DEBUG_TEMPLATES
  396. XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  397. "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret));
  398. #endif
  399. if (expr != NULL)
  400. xmlFree(expr);
  401. return(ret);
  402. }
  403. /**
  404. * xsltEvalStaticAttrValueTemplate:
  405. * @style: the XSLT stylesheet
  406. * @inst: the instruction (or LRE) in the stylesheet holding the
  407. * attribute with an AVT
  408. * @name: the attribute Name
  409. * @ns: the attribute namespace URI
  410. * @found: indicator whether the attribute is present
  411. *
  412. * Check if an attribute value template has a static value, i.e. the
  413. * attribute value does not contain expressions contained in curly braces ({})
  414. *
  415. * Returns the static string value or NULL, must be deallocated by the
  416. * caller.
  417. */
  418. const xmlChar *
  419. xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
  420. const xmlChar *name, const xmlChar *ns, int *found) {
  421. const xmlChar *ret;
  422. xmlChar *expr;
  423. if ((style == NULL) || (inst == NULL) || (name == NULL) ||
  424. (inst->type != XML_ELEMENT_NODE))
  425. return(NULL);
  426. expr = xsltGetNsProp(inst, name, ns);
  427. if (expr == NULL) {
  428. *found = 0;
  429. return(NULL);
  430. }
  431. *found = 1;
  432. ret = xmlStrchr(expr, '{');
  433. if (ret != NULL) {
  434. xmlFree(expr);
  435. return(NULL);
  436. }
  437. ret = xmlDictLookup(style->dict, expr, -1);
  438. xmlFree(expr);
  439. return(ret);
  440. }
  441. /**
  442. * xsltAttrTemplateProcess:
  443. * @ctxt: the XSLT transformation context
  444. * @target: the element where the attribute will be grafted
  445. * @attr: the attribute node of a literal result element
  446. *
  447. * Process one attribute of a Literal Result Element (in the stylesheet).
  448. * Evaluates Attribute Value Templates and copies the attribute over to
  449. * the result element.
  450. * This does *not* process attribute sets (xsl:use-attribute-set).
  451. *
  452. *
  453. * Returns the generated attribute node.
  454. */
  455. xmlAttrPtr
  456. xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
  457. xmlAttrPtr attr)
  458. {
  459. const xmlChar *value;
  460. xmlAttrPtr ret;
  461. if ((ctxt == NULL) || (attr == NULL) || (target == NULL) ||
  462. (target->type != XML_ELEMENT_NODE))
  463. return(NULL);
  464. if (attr->type != XML_ATTRIBUTE_NODE)
  465. return(NULL);
  466. /*
  467. * Skip all XSLT attributes.
  468. */
  469. #ifdef XSLT_REFACTORED
  470. if (attr->psvi == xsltXSLTAttrMarker)
  471. return(NULL);
  472. #else
  473. if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
  474. return(NULL);
  475. #endif
  476. /*
  477. * Get the value.
  478. */
  479. if (attr->children != NULL) {
  480. if ((attr->children->type != XML_TEXT_NODE) ||
  481. (attr->children->next != NULL))
  482. {
  483. xsltTransformError(ctxt, NULL, attr->parent,
  484. "Internal error: The children of an attribute node of a "
  485. "literal result element are not in the expected form.\n");
  486. return(NULL);
  487. }
  488. value = attr->children->content;
  489. if (value == NULL)
  490. value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
  491. } else
  492. value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
  493. /*
  494. * Overwrite duplicates.
  495. */
  496. ret = target->properties;
  497. while (ret != NULL) {
  498. if (((attr->ns != NULL) == (ret->ns != NULL)) &&
  499. xmlStrEqual(ret->name, attr->name) &&
  500. ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href)))
  501. {
  502. break;
  503. }
  504. ret = ret->next;
  505. }
  506. if (ret != NULL) {
  507. /* free the existing value */
  508. xmlFreeNodeList(ret->children);
  509. ret->children = ret->last = NULL;
  510. /*
  511. * Adjust ns-prefix if needed.
  512. */
  513. if ((ret->ns != NULL) &&
  514. (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix)))
  515. {
  516. ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
  517. }
  518. } else {
  519. /* create a new attribute */
  520. if (attr->ns != NULL)
  521. ret = xmlNewNsProp(target,
  522. xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
  523. attr->name, NULL);
  524. else
  525. ret = xmlNewNsProp(target, NULL, attr->name, NULL);
  526. }
  527. /*
  528. * Set the value.
  529. */
  530. if (ret != NULL) {
  531. xmlNodePtr text;
  532. text = xmlNewText(NULL);
  533. if (text != NULL) {
  534. ret->last = ret->children = text;
  535. text->parent = (xmlNodePtr) ret;
  536. text->doc = ret->doc;
  537. if (attr->psvi != NULL) {
  538. /*
  539. * Evaluate the Attribute Value Template.
  540. */
  541. xmlChar *val;
  542. val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
  543. if (val == NULL) {
  544. /*
  545. * TODO: Damn, we need an easy mechanism to report
  546. * qualified names!
  547. */
  548. if (attr->ns) {
  549. xsltTransformError(ctxt, NULL, attr->parent,
  550. "Internal error: Failed to evaluate the AVT "
  551. "of attribute '{%s}%s'.\n",
  552. attr->ns->href, attr->name);
  553. } else {
  554. xsltTransformError(ctxt, NULL, attr->parent,
  555. "Internal error: Failed to evaluate the AVT "
  556. "of attribute '%s'.\n",
  557. attr->name);
  558. }
  559. text->content = xmlStrdup(BAD_CAST "");
  560. } else {
  561. text->content = val;
  562. }
  563. } else if ((ctxt->internalized) && (target != NULL) &&
  564. (target->doc != NULL) &&
  565. (target->doc->dict == ctxt->dict) &&
  566. xmlDictOwns(ctxt->dict, value)) {
  567. text->content = (xmlChar *) value;
  568. } else {
  569. text->content = xmlStrdup(value);
  570. }
  571. }
  572. } else {
  573. if (attr->ns) {
  574. xsltTransformError(ctxt, NULL, attr->parent,
  575. "Internal error: Failed to create attribute '{%s}%s'.\n",
  576. attr->ns->href, attr->name);
  577. } else {
  578. xsltTransformError(ctxt, NULL, attr->parent,
  579. "Internal error: Failed to create attribute '%s'.\n",
  580. attr->name);
  581. }
  582. }
  583. return(ret);
  584. }
  585. /**
  586. * xsltAttrListTemplateProcess:
  587. * @ctxt: the XSLT transformation context
  588. * @target: the element where the attributes will be grafted
  589. * @attrs: the first attribute
  590. *
  591. * Processes all attributes of a Literal Result Element.
  592. * Attribute references are applied via xsl:use-attribute-set
  593. * attributes.
  594. * Copies all non XSLT-attributes over to the @target element
  595. * and evaluates Attribute Value Templates.
  596. *
  597. * Called by xsltApplySequenceConstructor() (transform.c).
  598. *
  599. * Returns a new list of attribute nodes, or NULL in case of error.
  600. * (Don't assign the result to @target->properties; if
  601. * the result is NULL, you'll get memory leaks, since the
  602. * attributes will be disattached.)
  603. */
  604. xmlAttrPtr
  605. xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt,
  606. xmlNodePtr target, xmlAttrPtr attrs)
  607. {
  608. xmlAttrPtr attr, copy, last = NULL;
  609. xmlNodePtr oldInsert, text;
  610. xmlNsPtr origNs = NULL, copyNs = NULL;
  611. const xmlChar *value;
  612. xmlChar *valueAVT;
  613. int hasAttr = 0;
  614. if ((ctxt == NULL) || (target == NULL) || (attrs == NULL) ||
  615. (target->type != XML_ELEMENT_NODE))
  616. return(NULL);
  617. oldInsert = ctxt->insert;
  618. ctxt->insert = target;
  619. /*
  620. * Apply attribute-sets.
  621. */
  622. attr = attrs;
  623. do {
  624. #ifdef XSLT_REFACTORED
  625. if ((attr->psvi == xsltXSLTAttrMarker) &&
  626. xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets"))
  627. {
  628. xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
  629. }
  630. #else
  631. if ((attr->ns != NULL) &&
  632. xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") &&
  633. xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
  634. {
  635. xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
  636. }
  637. #endif
  638. attr = attr->next;
  639. } while (attr != NULL);
  640. if (target->properties != NULL) {
  641. hasAttr = 1;
  642. }
  643. /*
  644. * Instantiate LRE-attributes.
  645. */
  646. attr = attrs;
  647. do {
  648. /*
  649. * Skip XSLT attributes.
  650. */
  651. #ifdef XSLT_REFACTORED
  652. if (attr->psvi == xsltXSLTAttrMarker) {
  653. goto next_attribute;
  654. }
  655. #else
  656. if ((attr->ns != NULL) &&
  657. xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
  658. {
  659. goto next_attribute;
  660. }
  661. #endif
  662. /*
  663. * Get the value.
  664. */
  665. if (attr->children != NULL) {
  666. if ((attr->children->type != XML_TEXT_NODE) ||
  667. (attr->children->next != NULL))
  668. {
  669. xsltTransformError(ctxt, NULL, attr->parent,
  670. "Internal error: The children of an attribute node of a "
  671. "literal result element are not in the expected form.\n");
  672. goto error;
  673. }
  674. value = attr->children->content;
  675. if (value == NULL)
  676. value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
  677. } else
  678. value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
  679. /*
  680. * Get the namespace. Avoid lookups of same namespaces.
  681. */
  682. if (attr->ns != origNs) {
  683. origNs = attr->ns;
  684. if (attr->ns != NULL) {
  685. #ifdef XSLT_REFACTORED
  686. copyNs = xsltGetSpecialNamespace(ctxt, attr->parent,
  687. attr->ns->href, attr->ns->prefix, target);
  688. #else
  689. copyNs = xsltGetNamespace(ctxt, attr->parent,
  690. attr->ns, target);
  691. #endif
  692. if (copyNs == NULL)
  693. goto error;
  694. } else
  695. copyNs = NULL;
  696. }
  697. /*
  698. * Create a new attribute.
  699. */
  700. if (hasAttr) {
  701. copy = xmlSetNsProp(target, copyNs, attr->name, NULL);
  702. } else {
  703. /*
  704. * Avoid checking for duplicate attributes if there aren't
  705. * any attribute sets.
  706. */
  707. copy = xmlNewDocProp(target->doc, attr->name, NULL);
  708. if (copy != NULL) {
  709. copy->ns = copyNs;
  710. /*
  711. * Attach it to the target element.
  712. */
  713. copy->parent = target;
  714. if (last == NULL) {
  715. target->properties = copy;
  716. last = copy;
  717. } else {
  718. last->next = copy;
  719. copy->prev = last;
  720. last = copy;
  721. }
  722. }
  723. }
  724. if (copy == NULL) {
  725. if (attr->ns) {
  726. xsltTransformError(ctxt, NULL, attr->parent,
  727. "Internal error: Failed to create attribute '{%s}%s'.\n",
  728. attr->ns->href, attr->name);
  729. } else {
  730. xsltTransformError(ctxt, NULL, attr->parent,
  731. "Internal error: Failed to create attribute '%s'.\n",
  732. attr->name);
  733. }
  734. goto error;
  735. }
  736. /*
  737. * Set the value.
  738. */
  739. text = xmlNewText(NULL);
  740. if (text != NULL) {
  741. copy->last = copy->children = text;
  742. text->parent = (xmlNodePtr) copy;
  743. text->doc = copy->doc;
  744. if (attr->psvi != NULL) {
  745. /*
  746. * Evaluate the Attribute Value Template.
  747. */
  748. valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
  749. if (valueAVT == NULL) {
  750. /*
  751. * TODO: Damn, we need an easy mechanism to report
  752. * qualified names!
  753. */
  754. if (attr->ns) {
  755. xsltTransformError(ctxt, NULL, attr->parent,
  756. "Internal error: Failed to evaluate the AVT "
  757. "of attribute '{%s}%s'.\n",
  758. attr->ns->href, attr->name);
  759. } else {
  760. xsltTransformError(ctxt, NULL, attr->parent,
  761. "Internal error: Failed to evaluate the AVT "
  762. "of attribute '%s'.\n",
  763. attr->name);
  764. }
  765. text->content = xmlStrdup(BAD_CAST "");
  766. goto error;
  767. } else {
  768. text->content = valueAVT;
  769. }
  770. } else if ((ctxt->internalized) &&
  771. (target->doc != NULL) &&
  772. (target->doc->dict == ctxt->dict) &&
  773. xmlDictOwns(ctxt->dict, value))
  774. {
  775. text->content = (xmlChar *) value;
  776. } else {
  777. text->content = xmlStrdup(value);
  778. }
  779. if ((copy != NULL) && (text != NULL) &&
  780. (xmlIsID(copy->doc, copy->parent, copy)))
  781. xmlAddID(NULL, copy->doc, text->content, copy);
  782. }
  783. next_attribute:
  784. attr = attr->next;
  785. } while (attr != NULL);
  786. ctxt->insert = oldInsert;
  787. return(target->properties);
  788. error:
  789. ctxt->insert = oldInsert;
  790. return(NULL);
  791. }
  792. /**
  793. * xsltTemplateProcess:
  794. * @ctxt: the XSLT transformation context
  795. * @node: the attribute template node
  796. *
  797. * Obsolete. Don't use it.
  798. *
  799. * Returns NULL.
  800. */
  801. xmlNodePtr *
  802. xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
  803. if (node == NULL)
  804. return(NULL);
  805. return(0);
  806. }