1 /*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "stdafx.h"
17
18 #include "runtime/parsing_and_serializing/parse_fragment.h"
19
20 #include <iostream>
21
22 #include "zorbatypes/URI.h"
23 #include "context/static_context.h"
24
25 #include "store/api/store.h"
26 #include "store/api/item.h"
27 #include "store/api/item_factory.h"
28 #include "store/api/load_properties.h"
29
30 #include "system/globalenv.h"
31
32 #include "types/schema/schema.h"
33 #include "types/schema/validate.h"
34
35
36 namespace zorba
37 {
38
39 /*******************************************************************************
40 14.9.1 fn-zorba-xml:parse
41 ********************************************************************************/
42
getFirstAttribute(store::Item_t node)43 store::Item_t getFirstAttribute(store::Item_t node)
44 {
45 store::Item_t attr;
46 store::Iterator_t attributes = node->getAttributes();
47 attributes->open();
48 attributes->next(attr);
49 attributes->close();
50 return attr;
51 }
52
processOptions(store::Item_t item,store::LoadProperties & props,static_context * theSctx,const QueryLoc & loc)53 void processOptions(store::Item_t item, store::LoadProperties& props, static_context* theSctx, const QueryLoc& loc)
54 {
55 URI lValidatedBaseUri;
56 store::Item_t child, tempItem;
57
58 if (item.getp() == NULL)
59 return;
60
61 #ifndef ZORBA_NO_XMLSCHEMA
62 if (item->isValidated())
63 {
64 if (item->getNodeName() == NULL
65 ||
66 item->getNodeName()->getNamespace() != static_context::ZORBA_XML_FN_OPTIONS_NS)
67 {
68 throw XQUERY_EXCEPTION(zerr::ZXQD0003_INCONSISTENT_PARSE_FRAGMENT_OPTIONS,
69 ERROR_PARAMS(ZED(ParseFragmentInvalidOptions)), ERROR_LOC( loc ));
70 }
71 }
72 else
73 {
74 tempItem = NULL; // used as the effectiveValidationValue()'s typeName
75 Validator::effectiveValidationValue(
76 item,
77 item,
78 tempItem,
79 theSctx->get_typemanager(),
80 ParseConstants::val_strict,
81 theSctx,
82 loc);
83 }
84 #endif
85
86 store::Iterator_t children = item->getChildren();
87 children->open();
88
89 while (children->next(child))
90 {
91 if (child->getNodeKind() != store::StoreConsts::elementNode)
92 continue;
93
94 if (child->getNodeName()->getLocalName() == "base-uri")
95 {
96 store::Item_t attr = getFirstAttribute(child);
97
98 try {
99 lValidatedBaseUri = URI(attr->getStringValue());
100 } catch (ZorbaException const& /* e */) {
101 throw XQUERY_EXCEPTION(
102 err::FODC0007,
103 ERROR_PARAMS( attr->getStringValue() ),
104 ERROR_LOC( loc )
105 );
106 }
107
108 if (!lValidatedBaseUri.is_absolute()) {
109 throw XQUERY_EXCEPTION(
110 err::FODC0007,
111 ERROR_PARAMS( lValidatedBaseUri.toString() ),
112 ERROR_LOC( loc )
113 );
114 }
115
116 props.setBaseUri(attr->getStringValue());
117 }
118 else if (child->getNodeName()->getLocalName() == "no-error")
119 props.setNoError(true);
120 else if (child->getNodeName()->getLocalName() == "strip-boundary-space")
121 props.setStripWhitespace(true);
122 else if (child->getNodeName()->getLocalName() == "schema-validate")
123 {
124 store::Item_t attr = getFirstAttribute(child);
125 if (attr->getStringValue() == "strict")
126 props.setSchemaStrictValidate(true);
127 else
128 props.setSchemaLaxValidate(true);
129 }
130 else if (child->getNodeName()->getLocalName() == "DTD-validate")
131 props.setDTDValidate(true);
132 else if (child->getNodeName()->getLocalName() == "DTD-load")
133 props.setDTDLoad(true);
134 else if (child->getNodeName()->getLocalName() == "default-DTD-attributes")
135 props.setDefaultDTDAttributes(true);
136 else if (child->getNodeName()->getLocalName() == "parse-external-parsed-entity")
137 {
138 props.setParseExternalParsedEntity(true);
139 store::Item_t attr;
140 store::Iterator_t attribs = child->getAttributes();
141 attribs->open();
142 while (attribs->next(attr))
143 {
144 if (attr->getNodeName()->getLocalName() == "skip-root-nodes")
145 props.setSkipRootNodes(ztd::aton<xs_int>(attr->getStringValue().c_str()));
146 else if (attr->getNodeName()->getLocalName() == "skip-top-level-text-nodes")
147 props.setSkipTopLevelTextNodes(true);
148 else if (attr->getNodeName()->getLocalName() == "error-on-doctype")
149 props.setErrorOnDoctype(true);
150 }
151 attribs->close();
152 }
153 else if (child->getNodeName()->getLocalName() == "substitute-entities")
154 props.setSubstituteEntities(true);
155 else if (child->getNodeName()->getLocalName() == "xinclude-substitutions")
156 props.setXincludeSubstitutions(true);
157 else if (child->getNodeName()->getLocalName() == "remove-redundant-ns")
158 props.setRemoveRedundantNS(true);
159 else if (child->getNodeName()->getLocalName() == "no-CDATA")
160 props.setNoCDATA(true);
161 else if (child->getNodeName()->getLocalName() == "no-xinclude-nodes")
162 props.setNoXIncludeNodes(true);
163 }
164
165 children->close();
166
167 if (props.getSchemaLaxValidate() + props.getSchemaStrictValidate() +
168 props.getDTDValidate() + props.getParseExternalParsedEntity() > 1)
169 {
170 throw XQUERY_EXCEPTION(zerr::ZXQD0003_INCONSISTENT_PARSE_FRAGMENT_OPTIONS,
171 ERROR_PARAMS(ZED(ParseFragmentOptionCombinationNotAllowed)), ERROR_LOC( loc ));
172 }
173 }
174
reset(PlanState & planState)175 void FnZorbaParseXmlFragmentIteratorState::reset(PlanState& planState)
176 {
177 PlanIteratorState::reset(planState);
178 theFragmentStream.reset();
179 theProperties.reset();
180 theProperties.setStoreDocument(false);
181 baseUri = "";
182 docUri = "";
183 }
184
nextImpl(store::Item_t & result,PlanState & planState) const185 bool FnZorbaParseXmlFragmentIterator::nextImpl(store::Item_t& result, PlanState& planState) const
186 {
187 store::Store& lStore = GENV.getStore();
188 zstring docString;
189 store::Item_t tempItem;
190 bool validated = true;
191
192 FnZorbaParseXmlFragmentIteratorState* state;
193 DEFAULT_STACK_INIT(FnZorbaParseXmlFragmentIteratorState, state, planState);
194
195 if (consumeNext(result, theChildren[0].getp(), planState))
196 {
197 if (result->isStreamable())
198 {
199 state->theFragmentStream.theStream = &result->getStream();
200 state->theFragmentStream.setStreamReleaser(result->getStreamReleaser());
201 result->setStreamReleaser(nullptr);
202 }
203 else
204 {
205 result->getStringValue2(docString);
206 state->theFragmentStream.theIss = new std::istringstream(docString.c_str());
207 state->theFragmentStream.theStream = state->theFragmentStream.theIss;
208 }
209
210 // read options
211 consumeNext(tempItem, theChildren[1].getp(), planState);
212 state->theProperties.setBaseUri(theSctx->get_base_uri());
213 state->theProperties.setStoreDocument(false);
214 processOptions(tempItem, state->theProperties, theSctx, loc);
215 state->theProperties.setCreateDocParentLink(false);
216
217 // baseURI serves both as the base URI used by the XML parser
218 // to resolve relative entity references within the document,
219 // and as the base URI of the document node that is returned.
220 state->baseUri = state->theProperties.getBaseUri();
221 state->docUri = state->theProperties.getBaseUri();
222
223
224 ////////////////////////////////////////////////////////////////////////
225 // External parsed entity processing
226 ////////////////////////////////////////////////////////////////////////
227 if (state->theProperties.getParseExternalParsedEntity())
228 {
229 state->theFragmentStream.root_elements_to_skip = state->theProperties.getSkipRootNodes();
230
231 while ( ! state->theFragmentStream.stream_is_consumed())
232 {
233 try {
234 result = lStore.loadDocument(state->baseUri, state->docUri, state->theFragmentStream, state->theProperties);
235 } catch (ZorbaException const& e) {
236 if ( ! state->theProperties.getNoError())
237 throw XQUERY_EXCEPTION( err::FODC0006, ERROR_PARAMS("parse-xml:parse()", e.what()), ERROR_LOC( loc ));
238 else
239 result = NULL;
240 }
241
242 if (result == NULL)
243 continue;
244
245 // Return the children of document node
246 state->theFragmentStream.children = result->getChildren();
247 while (state->theFragmentStream.children->next(result) && result != NULL)
248 {
249 if (state->theProperties.getSkipTopLevelTextNodes() && result->getNodeKind() == store::StoreConsts::textNode)
250 continue;
251
252 STACK_PUSH(true, state);
253 }
254 }
255 }
256 ////////////////////////////////////////////////////////////////////////
257 // XML document processing
258 ////////////////////////////////////////////////////////////////////////
259 else // if (!state->theProperties.getEnableExtParsedEntity())
260 {
261 try {
262 result = lStore.loadDocument(state->baseUri, state->docUri, *state->theFragmentStream.theStream, state->theProperties);
263 } catch (ZorbaException const& e) {
264 if ( ! state->theProperties.getNoError())
265 throw XQUERY_EXCEPTION( err::FODC0006, ERROR_PARAMS("parse-xml:parse()", e.what()), ERROR_LOC( loc ));
266 else
267 result = NULL;
268 }
269
270 if (result != NULL)
271 {
272 #ifndef ZORBA_NO_XMLSCHEMA
273 if (state->theProperties.getSchemaLaxValidate() || state->theProperties.getSchemaStrictValidate())
274 {
275 try
276 {
277 tempItem = NULL; // used as the effectiveValidationValue()'s typeName
278 validated = Validator::effectiveValidationValue(
279 result,
280 result,
281 tempItem,
282 theSctx->get_typemanager(),
283 state->theProperties.getSchemaLaxValidate() ? ParseConstants::val_lax : ParseConstants::val_strict,
284 theSctx,
285 this->loc);
286 }
287 catch (ZorbaException& /*e*/)
288 {
289 if ( ! state->theProperties.getNoError())
290 throw;
291 else
292 {
293 result = NULL;
294 validated = false;
295 }
296 }
297 }
298 #endif
299 // Ignore the schema validation options if Zorba is built without schema support
300
301 STACK_PUSH(validated, state);
302 } // if (result != NULL)
303 } // if (state->theProperties.getEnableExtParsedEntity())
304 } // if (consumeNext(result, theChildren[0].getp(), planState))
305
306 STACK_END(state);
307 }
308
309
310 /*******************************************************************************
311 14.9.2 fn:parse-xml-fragment
312 ********************************************************************************/
nextImpl(store::Item_t & result,PlanState & planState) const313 bool FnParseXmlFragmentIterator::nextImpl(store::Item_t& result, PlanState& planState) const
314 {
315 zstring docString;
316
317 FnParseXmlFragmentIteratorState* state;
318 DEFAULT_STACK_INIT(FnParseXmlFragmentIteratorState, state, planState);
319
320 if (consumeNext(result, theChildren[0].getp(), planState))
321 {
322 if (result->isStreamable())
323 {
324 state->theFragmentStream.theStream = &result->getStream();
325 }
326 else
327 {
328 result->getStringValue2(docString);
329 state->theFragmentStream.theIss = new std::istringstream(docString.c_str());
330 state->theFragmentStream.theStream = state->theFragmentStream.theIss;
331 }
332
333 state->theProperties.setBaseUri(theSctx->get_base_uri());
334 state->baseUri = state->theProperties.getBaseUri();
335 state->theProperties.setParseExternalParsedEntity(true);
336 state->theFragmentStream.only_one_doc_node = 1; // create only one document node holding all fragment nodes
337
338 try {
339 state->theProperties.setStoreDocument(false);
340 result = GENV.getStore().loadDocument(state->baseUri, state->docUri, state->theFragmentStream, state->theProperties);
341 } catch (ZorbaException const& e) {
342 if( ! state->theProperties.getNoError())
343 throw XQUERY_EXCEPTION(err::FODC0006, ERROR_PARAMS("fn:parse-xml-fragment()", e.what() ), ERROR_LOC(loc));
344 else
345 result = NULL;
346 }
347
348 if (result != NULL)
349 STACK_PUSH(true, state);
350 } // if
351
352 STACK_END(state);
353 }
354
reset(PlanState & planState)355 void FnParseXmlFragmentIteratorState::reset(PlanState& planState)
356 {
357 PlanIteratorState::reset(planState);
358 theFragmentStream.reset();
359 theProperties.reset();
360 theProperties.setStoreDocument(false);
361 baseUri = "";
362 docUri = "";
363 }
364
365 } /* namespace zorba */
366