1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski 
25*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
26*b1cdbd2cSJim Jagielski #include "precompiled_forms.hxx"
27*b1cdbd2cSJim Jagielski #include <string.h>
28*b1cdbd2cSJim Jagielski #include <sal/types.h>
29*b1cdbd2cSJim Jagielski #include <rtl/alloc.h>
30*b1cdbd2cSJim Jagielski #include <rtl/ustring.hxx>
31*b1cdbd2cSJim Jagielski #include <rtl/string.hxx>
32*b1cdbd2cSJim Jagielski #include <rtl/ustrbuf.hxx>
33*b1cdbd2cSJim Jagielski #include <rtl/strbuf.hxx>
34*b1cdbd2cSJim Jagielski #include <tools/date.hxx>
35*b1cdbd2cSJim Jagielski #include <tools/time.hxx>
36*b1cdbd2cSJim Jagielski #include <tools/datetime.hxx>
37*b1cdbd2cSJim Jagielski 
38*b1cdbd2cSJim Jagielski #include <com/sun/star/uno/Reference.hxx>
39*b1cdbd2cSJim Jagielski #include <com/sun/star/uno/Sequence.hxx>
40*b1cdbd2cSJim Jagielski #include <com/sun/star/uno/Any.hxx>
41*b1cdbd2cSJim Jagielski #include <com/sun/star/xforms/XModel.hpp>
42*b1cdbd2cSJim Jagielski #include <com/sun/star/xml/dom/XNode.hpp>
43*b1cdbd2cSJim Jagielski #include <com/sun/star/xml/dom/XDocument.hpp>
44*b1cdbd2cSJim Jagielski #include <com/sun/star/lang/XUnoTunnel.hpp>
45*b1cdbd2cSJim Jagielski 
46*b1cdbd2cSJim Jagielski #include "xpathlib.hxx"
47*b1cdbd2cSJim Jagielski 
48*b1cdbd2cSJim Jagielski #include "extension.hxx"
49*b1cdbd2cSJim Jagielski 
50*b1cdbd2cSJim Jagielski // C interface
51*b1cdbd2cSJim Jagielski 
52*b1cdbd2cSJim Jagielski using namespace com::sun::star::uno;
53*b1cdbd2cSJim Jagielski using namespace com::sun::star::xml::dom;
54*b1cdbd2cSJim Jagielski using namespace com::sun::star::xforms;
55*b1cdbd2cSJim Jagielski using namespace com::sun::star::lang;
56*b1cdbd2cSJim Jagielski 
xforms_lookupFunc(void *,const xmlChar * xname,const xmlChar *)57*b1cdbd2cSJim Jagielski xmlXPathFunction xforms_lookupFunc(void *, const xmlChar *xname, const xmlChar *)
58*b1cdbd2cSJim Jagielski {
59*b1cdbd2cSJim Jagielski 
60*b1cdbd2cSJim Jagielski     const char *name = (char *)xname;
61*b1cdbd2cSJim Jagielski     if (strcmp("boolean-from-string", name)==0)
62*b1cdbd2cSJim Jagielski         return xforms_booleanFromStringFunction;
63*b1cdbd2cSJim Jagielski     else if ((strcmp("if", name))==0)
64*b1cdbd2cSJim Jagielski         return xforms_ifFunction;
65*b1cdbd2cSJim Jagielski     else if ((strcmp("avg", name))==0)
66*b1cdbd2cSJim Jagielski         return xforms_avgFunction;
67*b1cdbd2cSJim Jagielski     else if ((strcmp("min", name))==0)
68*b1cdbd2cSJim Jagielski         return xforms_minFunction;
69*b1cdbd2cSJim Jagielski     else if ((strcmp("max", name))==0)
70*b1cdbd2cSJim Jagielski         return xforms_maxFunction;
71*b1cdbd2cSJim Jagielski     else if ((strcmp("count-non-empty", name))==0)
72*b1cdbd2cSJim Jagielski         return xforms_countNonEmptyFunction;
73*b1cdbd2cSJim Jagielski     else if ((strcmp("index", name))==0)
74*b1cdbd2cSJim Jagielski         return xforms_indexFunction;
75*b1cdbd2cSJim Jagielski     else if ((strcmp("property", name))==0)
76*b1cdbd2cSJim Jagielski         return xforms_propertyFunction;
77*b1cdbd2cSJim Jagielski     else if ((strcmp("now", name))==0)
78*b1cdbd2cSJim Jagielski         return xforms_nowFunction;
79*b1cdbd2cSJim Jagielski     else if ((strcmp("days-from-date", name))==0)
80*b1cdbd2cSJim Jagielski         return xforms_daysFromDateFunction;
81*b1cdbd2cSJim Jagielski     else if ((strcmp("seconds-from-dateTime", name))==0)
82*b1cdbd2cSJim Jagielski         return xforms_secondsFromDateTimeFunction;
83*b1cdbd2cSJim Jagielski     else if ((strcmp("seconds", name))==0)
84*b1cdbd2cSJim Jagielski         return xforms_secondsFuction;
85*b1cdbd2cSJim Jagielski     else if ((strcmp("months", name))==0)
86*b1cdbd2cSJim Jagielski         return xforms_monthsFuction;
87*b1cdbd2cSJim Jagielski     else if ((strcmp("instance", name))==0)
88*b1cdbd2cSJim Jagielski         return xforms_instanceFuction;
89*b1cdbd2cSJim Jagielski     else if ((strcmp("current", name))==0)
90*b1cdbd2cSJim Jagielski         return xforms_currentFunction;
91*b1cdbd2cSJim Jagielski     else
92*b1cdbd2cSJim Jagielski         return NULL;
93*b1cdbd2cSJim Jagielski }
94*b1cdbd2cSJim Jagielski 
95*b1cdbd2cSJim Jagielski // boolean functions
xforms_booleanFromStringFunction(xmlXPathParserContextPtr ctxt,int nargs)96*b1cdbd2cSJim Jagielski void xforms_booleanFromStringFunction(xmlXPathParserContextPtr ctxt, int nargs)
97*b1cdbd2cSJim Jagielski {
98*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
99*b1cdbd2cSJim Jagielski     xmlChar *pString = xmlXPathPopString(ctxt);
100*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
101*b1cdbd2cSJim Jagielski     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
102*b1cdbd2cSJim Jagielski     if (aString.equalsIgnoreAsciiCaseAscii("true") || aString.equalsIgnoreAsciiCaseAscii("1"))
103*b1cdbd2cSJim Jagielski         xmlXPathReturnTrue(ctxt);
104*b1cdbd2cSJim Jagielski     else if (aString.equalsIgnoreAsciiCaseAscii("false") || aString.equalsIgnoreAsciiCaseAscii("0"))
105*b1cdbd2cSJim Jagielski         xmlXPathReturnFalse(ctxt);
106*b1cdbd2cSJim Jagielski     else
107*b1cdbd2cSJim Jagielski         XP_ERROR(XPATH_NUMBER_ERROR);
108*b1cdbd2cSJim Jagielski }
109*b1cdbd2cSJim Jagielski 
xforms_ifFunction(xmlXPathParserContextPtr ctxt,int nargs)110*b1cdbd2cSJim Jagielski void xforms_ifFunction(xmlXPathParserContextPtr ctxt, int nargs)
111*b1cdbd2cSJim Jagielski {
112*b1cdbd2cSJim Jagielski     if (nargs != 3) XP_ERROR(XPATH_INVALID_ARITY);
113*b1cdbd2cSJim Jagielski     xmlChar *s2 = xmlXPathPopString(ctxt);
114*b1cdbd2cSJim Jagielski 
115*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
116*b1cdbd2cSJim Jagielski     xmlChar *s1 = xmlXPathPopString(ctxt);
117*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
118*b1cdbd2cSJim Jagielski     bool aBool = xmlXPathPopBoolean(ctxt);
119*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
120*b1cdbd2cSJim Jagielski 
121*b1cdbd2cSJim Jagielski     if (aBool)
122*b1cdbd2cSJim Jagielski         xmlXPathReturnString(ctxt, s1);
123*b1cdbd2cSJim Jagielski     else
124*b1cdbd2cSJim Jagielski         xmlXPathReturnString(ctxt, s2);
125*b1cdbd2cSJim Jagielski 
126*b1cdbd2cSJim Jagielski }
127*b1cdbd2cSJim Jagielski 
128*b1cdbd2cSJim Jagielski // Number Functions
xforms_avgFunction(xmlXPathParserContextPtr ctxt,int nargs)129*b1cdbd2cSJim Jagielski void xforms_avgFunction(xmlXPathParserContextPtr ctxt, int nargs)
130*b1cdbd2cSJim Jagielski {
131*b1cdbd2cSJim Jagielski     // use sum(), div() and count()
132*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
133*b1cdbd2cSJim Jagielski 
134*b1cdbd2cSJim Jagielski     // save nodeset
135*b1cdbd2cSJim Jagielski     xmlXPathObjectPtr pObject = valuePop(ctxt);
136*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
137*b1cdbd2cSJim Jagielski     //push back a copy
138*b1cdbd2cSJim Jagielski     valuePush(ctxt, xmlXPathObjectCopy(pObject));
139*b1cdbd2cSJim Jagielski     // get the Sum
140*b1cdbd2cSJim Jagielski     xmlXPathSumFunction(ctxt, 1);
141*b1cdbd2cSJim Jagielski     double nSum = xmlXPathPopNumber(ctxt);
142*b1cdbd2cSJim Jagielski     // push a copy once more
143*b1cdbd2cSJim Jagielski     valuePush(ctxt, xmlXPathObjectCopy(pObject));
144*b1cdbd2cSJim Jagielski     xmlXPathCountFunction(ctxt, 1);
145*b1cdbd2cSJim Jagielski     double nCount = xmlXPathPopNumber(ctxt);
146*b1cdbd2cSJim Jagielski     // push args for div()
147*b1cdbd2cSJim Jagielski     xmlXPathReturnNumber(ctxt, nSum);
148*b1cdbd2cSJim Jagielski     xmlXPathReturnNumber(ctxt, nCount);
149*b1cdbd2cSJim Jagielski     xmlXPathDivValues(ctxt);
150*b1cdbd2cSJim Jagielski     // the result is now on the ctxt stack
151*b1cdbd2cSJim Jagielski     xmlXPathFreeObject(pObject);
152*b1cdbd2cSJim Jagielski }
153*b1cdbd2cSJim Jagielski 
xforms_minFunction(xmlXPathParserContextPtr ctxt,int nargs)154*b1cdbd2cSJim Jagielski void xforms_minFunction(xmlXPathParserContextPtr ctxt, int nargs)
155*b1cdbd2cSJim Jagielski {
156*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
157*b1cdbd2cSJim Jagielski     xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt);
158*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
159*b1cdbd2cSJim Jagielski     double nMinimum = 0;
160*b1cdbd2cSJim Jagielski     double nNumber = 0;
161*b1cdbd2cSJim Jagielski     for (int i = 0; i <  xmlXPathNodeSetGetLength(pNodeSet); i++)
162*b1cdbd2cSJim Jagielski     {
163*b1cdbd2cSJim Jagielski         nNumber = xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pNodeSet, i));
164*b1cdbd2cSJim Jagielski         if (xmlXPathIsNaN(nNumber))
165*b1cdbd2cSJim Jagielski         {
166*b1cdbd2cSJim Jagielski             xmlXPathReturnNumber(ctxt, xmlXPathNAN);
167*b1cdbd2cSJim Jagielski             return;
168*b1cdbd2cSJim Jagielski         }
169*b1cdbd2cSJim Jagielski         if (i == 0)
170*b1cdbd2cSJim Jagielski             nMinimum = nNumber;
171*b1cdbd2cSJim Jagielski         else if (nNumber < nMinimum)
172*b1cdbd2cSJim Jagielski             nMinimum = nNumber;
173*b1cdbd2cSJim Jagielski     }
174*b1cdbd2cSJim Jagielski     xmlXPathReturnNumber(ctxt, nMinimum);
175*b1cdbd2cSJim Jagielski }
176*b1cdbd2cSJim Jagielski 
xforms_maxFunction(xmlXPathParserContextPtr ctxt,int nargs)177*b1cdbd2cSJim Jagielski void xforms_maxFunction(xmlXPathParserContextPtr ctxt, int nargs)
178*b1cdbd2cSJim Jagielski {
179*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
180*b1cdbd2cSJim Jagielski     xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt);
181*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
182*b1cdbd2cSJim Jagielski     double nMaximum = 0;
183*b1cdbd2cSJim Jagielski     double nNumber = 0;
184*b1cdbd2cSJim Jagielski     for (int i = 0; i <  xmlXPathNodeSetGetLength(pNodeSet); i++)
185*b1cdbd2cSJim Jagielski     {
186*b1cdbd2cSJim Jagielski         nNumber = xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pNodeSet, i));
187*b1cdbd2cSJim Jagielski         if (xmlXPathIsNaN(nNumber))
188*b1cdbd2cSJim Jagielski         {
189*b1cdbd2cSJim Jagielski             xmlXPathReturnNumber(ctxt, xmlXPathNAN);
190*b1cdbd2cSJim Jagielski             return;
191*b1cdbd2cSJim Jagielski         }
192*b1cdbd2cSJim Jagielski         if (i == 0)
193*b1cdbd2cSJim Jagielski             nMaximum = nNumber;
194*b1cdbd2cSJim Jagielski         else if (nNumber > nMaximum)
195*b1cdbd2cSJim Jagielski             nMaximum = nNumber;
196*b1cdbd2cSJim Jagielski     }
197*b1cdbd2cSJim Jagielski     xmlXPathReturnNumber(ctxt, nMaximum);
198*b1cdbd2cSJim Jagielski }
xforms_countNonEmptyFunction(xmlXPathParserContextPtr ctxt,int nargs)199*b1cdbd2cSJim Jagielski void xforms_countNonEmptyFunction(xmlXPathParserContextPtr ctxt, int nargs)
200*b1cdbd2cSJim Jagielski {
201*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
202*b1cdbd2cSJim Jagielski     xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt);
203*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
204*b1cdbd2cSJim Jagielski     xmlChar *aString;
205*b1cdbd2cSJim Jagielski     sal_Int32 nNotEmpty = 0;
206*b1cdbd2cSJim Jagielski     for (int i = 0; i <  xmlXPathNodeSetGetLength(pNodeSet); i++)
207*b1cdbd2cSJim Jagielski     {
208*b1cdbd2cSJim Jagielski         aString = xmlXPathCastNodeToString(xmlXPathNodeSetItem(pNodeSet, i));
209*b1cdbd2cSJim Jagielski         if (strlen((char*)aString) > 0) nNotEmpty++;
210*b1cdbd2cSJim Jagielski     }
211*b1cdbd2cSJim Jagielski     xmlXPathReturnNumber(ctxt, nNotEmpty);
212*b1cdbd2cSJim Jagielski }
xforms_indexFunction(xmlXPathParserContextPtr,int)213*b1cdbd2cSJim Jagielski void xforms_indexFunction(xmlXPathParserContextPtr /*ctxt*/, int /*nargs*/)
214*b1cdbd2cSJim Jagielski {
215*b1cdbd2cSJim Jagielski     // function index takes a string argument that is the IDREF of a
216*b1cdbd2cSJim Jagielski     // 'repeat' and returns the current 1-based position of the repeat
217*b1cdbd2cSJim Jagielski     // index of the identified repeat -- see xforms/9.3.1
218*b1cdbd2cSJim Jagielski 
219*b1cdbd2cSJim Jagielski     // doc.getElementByID
220*b1cdbd2cSJim Jagielski     // (...)
221*b1cdbd2cSJim Jagielski }
222*b1cdbd2cSJim Jagielski 
223*b1cdbd2cSJim Jagielski // String Functions
224*b1cdbd2cSJim Jagielski static const char* _version = "1.0";
225*b1cdbd2cSJim Jagielski static const char* _conformance = "conformance";
xforms_propertyFunction(xmlXPathParserContextPtr ctxt,int nargs)226*b1cdbd2cSJim Jagielski void xforms_propertyFunction(xmlXPathParserContextPtr ctxt, int nargs)
227*b1cdbd2cSJim Jagielski {
228*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
229*b1cdbd2cSJim Jagielski     xmlChar* pString = xmlXPathPopString(ctxt);
230*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
231*b1cdbd2cSJim Jagielski     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
232*b1cdbd2cSJim Jagielski     if (aString.equalsIgnoreAsciiCaseAscii("version"))
233*b1cdbd2cSJim Jagielski         xmlXPathReturnString(ctxt, (xmlChar*)_version);
234*b1cdbd2cSJim Jagielski     else if (aString.equalsIgnoreAsciiCaseAscii("conformance-level"))
235*b1cdbd2cSJim Jagielski         xmlXPathReturnString(ctxt, (xmlChar*)_conformance);
236*b1cdbd2cSJim Jagielski     else
237*b1cdbd2cSJim Jagielski         xmlXPathReturnEmptyString(ctxt);
238*b1cdbd2cSJim Jagielski }
239*b1cdbd2cSJim Jagielski 
240*b1cdbd2cSJim Jagielski // Date and Time Functions
241*b1cdbd2cSJim Jagielski 
makeDateTimeString(const DateTime & aDateTime,sal_Bool bUTC=sal_True)242*b1cdbd2cSJim Jagielski static ::rtl::OString makeDateTimeString (const DateTime& aDateTime, sal_Bool bUTC = sal_True)
243*b1cdbd2cSJim Jagielski {
244*b1cdbd2cSJim Jagielski     ::rtl::OStringBuffer aDateTimeString;
245*b1cdbd2cSJim Jagielski     aDateTimeString.append((sal_Int32)aDateTime.GetYear());
246*b1cdbd2cSJim Jagielski     aDateTimeString.append("-");
247*b1cdbd2cSJim Jagielski     if (aDateTime.GetMonth()<10) aDateTimeString.append("0");
248*b1cdbd2cSJim Jagielski     aDateTimeString.append((sal_Int32)aDateTime.GetMonth());
249*b1cdbd2cSJim Jagielski     aDateTimeString.append("-");
250*b1cdbd2cSJim Jagielski     if (aDateTime.GetDay()<10) aDateTimeString.append("0");
251*b1cdbd2cSJim Jagielski     aDateTimeString.append((sal_Int32)aDateTime.GetDay());
252*b1cdbd2cSJim Jagielski     aDateTimeString.append("T");
253*b1cdbd2cSJim Jagielski     if (aDateTime.GetHour()<10) aDateTimeString.append("0");
254*b1cdbd2cSJim Jagielski     aDateTimeString.append((sal_Int32)aDateTime.GetHour());
255*b1cdbd2cSJim Jagielski     aDateTimeString.append(":");
256*b1cdbd2cSJim Jagielski     if (aDateTime.GetMin()<10) aDateTimeString.append("0");
257*b1cdbd2cSJim Jagielski     aDateTimeString.append((sal_Int32)aDateTime.GetMin());
258*b1cdbd2cSJim Jagielski     aDateTimeString.append(":");
259*b1cdbd2cSJim Jagielski     if (aDateTime.GetSec()<10) aDateTimeString.append("0");
260*b1cdbd2cSJim Jagielski     aDateTimeString.append((sal_Int32)aDateTime.GetSec());
261*b1cdbd2cSJim Jagielski     if (bUTC) aDateTimeString.append("Z");
262*b1cdbd2cSJim Jagielski 
263*b1cdbd2cSJim Jagielski     return aDateTimeString.makeStringAndClear();
264*b1cdbd2cSJim Jagielski }
265*b1cdbd2cSJim Jagielski 
266*b1cdbd2cSJim Jagielski // returns current system date and time in canonical xsd:dateTime
267*b1cdbd2cSJim Jagielski // format
xforms_nowFunction(xmlXPathParserContextPtr ctxt,int)268*b1cdbd2cSJim Jagielski void xforms_nowFunction(xmlXPathParserContextPtr ctxt, int /*nargs*/)
269*b1cdbd2cSJim Jagielski {
270*b1cdbd2cSJim Jagielski     /*
271*b1cdbd2cSJim Jagielski     A single lexical representation, which is a subset of the lexical representations
272*b1cdbd2cSJim Jagielski     allowed by [ISO 8601], is allowed for dateTime. This lexical representation is the
273*b1cdbd2cSJim Jagielski     [ISO 8601] extended format CCYY-MM-DDThh:mm:ss where "CC" represents the century,
274*b1cdbd2cSJim Jagielski     "YY" the year, "MM" the month and "DD" the day, preceded by an optional leading "-"
275*b1cdbd2cSJim Jagielski     sign to indicate a negative number. If the sign is omitted, "+" is assumed. The letter
276*b1cdbd2cSJim Jagielski     "T" is the date/time separator and "hh", "mm", "ss" represent hour, minute and second
277*b1cdbd2cSJim Jagielski     respectively.
278*b1cdbd2cSJim Jagielski     */
279*b1cdbd2cSJim Jagielski 
280*b1cdbd2cSJim Jagielski     /*
281*b1cdbd2cSJim Jagielski     3.2.7.2 Canonical representation
282*b1cdbd2cSJim Jagielski     The canonical representation for dateTime is defined by prohibiting certain options
283*b1cdbd2cSJim Jagielski     from the Lexical representation (par.3.2.7.1). Specifically, either the time zone must
284*b1cdbd2cSJim Jagielski     be omitted or, if present, the time zone must be Coordinated Universal Time (UTC)
285*b1cdbd2cSJim Jagielski     indicated by a "Z".
286*b1cdbd2cSJim Jagielski     */
287*b1cdbd2cSJim Jagielski     DateTime aDateTime;
288*b1cdbd2cSJim Jagielski     ::rtl::OString aDateTimeString = makeDateTimeString(aDateTime);
289*b1cdbd2cSJim Jagielski     xmlChar *pString = static_cast<xmlChar*>(xmlMalloc(aDateTimeString.getLength()+1));
290*b1cdbd2cSJim Jagielski     strncpy((char*)pString, (char*)aDateTimeString.getStr(), aDateTimeString.getLength());
291*b1cdbd2cSJim Jagielski     pString[aDateTimeString.getLength()] = 0;
292*b1cdbd2cSJim Jagielski     xmlXPathReturnString(ctxt, pString);
293*b1cdbd2cSJim Jagielski }
294*b1cdbd2cSJim Jagielski 
parseDateTime(const::rtl::OUString & aString,DateTime & aDateTime)295*b1cdbd2cSJim Jagielski static sal_Bool parseDateTime(const ::rtl::OUString& aString, DateTime& aDateTime)
296*b1cdbd2cSJim Jagielski {
297*b1cdbd2cSJim Jagielski     // take apart a canonical literal xsd:dateTime string
298*b1cdbd2cSJim Jagielski     //CCYY-MM-DDThh:mm:ss(Z)
299*b1cdbd2cSJim Jagielski 
300*b1cdbd2cSJim Jagielski     ::rtl::OUString aDateTimeString = aString.trim();
301*b1cdbd2cSJim Jagielski 
302*b1cdbd2cSJim Jagielski     // check length
303*b1cdbd2cSJim Jagielski     if (aDateTimeString.getLength() < 19 || aDateTimeString.getLength() > 20)
304*b1cdbd2cSJim Jagielski         return sal_False;
305*b1cdbd2cSJim Jagielski 
306*b1cdbd2cSJim Jagielski     sal_Int32 nDateLength = 10;
307*b1cdbd2cSJim Jagielski     sal_Int32 nTimeLength = 8;
308*b1cdbd2cSJim Jagielski 
309*b1cdbd2cSJim Jagielski     ::rtl::OUString aDateTimeSep = ::rtl::OUString::createFromAscii("T");
310*b1cdbd2cSJim Jagielski     ::rtl::OUString aDateSep = ::rtl::OUString::createFromAscii("-");
311*b1cdbd2cSJim Jagielski     ::rtl::OUString aTimeSep = ::rtl::OUString::createFromAscii(":");
312*b1cdbd2cSJim Jagielski     ::rtl::OUString aUTCString = ::rtl::OUString::createFromAscii("Z");
313*b1cdbd2cSJim Jagielski 
314*b1cdbd2cSJim Jagielski     ::rtl::OUString aDateString = aDateTimeString.copy(0, nDateLength);
315*b1cdbd2cSJim Jagielski     ::rtl::OUString aTimeString = aDateTimeString.copy(nDateLength+1, nTimeLength);
316*b1cdbd2cSJim Jagielski 
317*b1cdbd2cSJim Jagielski     sal_Int32 nIndex = 0;
318*b1cdbd2cSJim Jagielski     sal_Int32 nYear = aDateString.getToken(0, '-', nIndex).toInt32();
319*b1cdbd2cSJim Jagielski     sal_Int32 nMonth = aDateString.getToken(0, '-', nIndex).toInt32();
320*b1cdbd2cSJim Jagielski     sal_Int32 nDay = aDateString.getToken(0, '-', nIndex).toInt32();
321*b1cdbd2cSJim Jagielski     nIndex = 0;
322*b1cdbd2cSJim Jagielski     sal_Int32 nHour = aTimeString.getToken(0, ':', nIndex).toInt32();
323*b1cdbd2cSJim Jagielski     sal_Int32 nMinute = aTimeString.getToken(0, ':', nIndex).toInt32();
324*b1cdbd2cSJim Jagielski     sal_Int32 nSecond = aTimeString.getToken(0, ':', nIndex).toInt32();
325*b1cdbd2cSJim Jagielski 
326*b1cdbd2cSJim Jagielski     Date tmpDate((sal_uInt16)nDay, (sal_uInt16)nMonth, (sal_uInt16)nYear);
327*b1cdbd2cSJim Jagielski     Time tmpTime(nHour, nMinute, nSecond);
328*b1cdbd2cSJim Jagielski     DateTime tmpDateTime(tmpDate, tmpTime);
329*b1cdbd2cSJim Jagielski     if (aString.indexOf(aUTCString) < 0)
330*b1cdbd2cSJim Jagielski         tmpDateTime.ConvertToUTC();
331*b1cdbd2cSJim Jagielski 
332*b1cdbd2cSJim Jagielski     aDateTime = tmpDateTime;
333*b1cdbd2cSJim Jagielski 
334*b1cdbd2cSJim Jagielski     return sal_True;
335*b1cdbd2cSJim Jagielski }
336*b1cdbd2cSJim Jagielski 
337*b1cdbd2cSJim Jagielski 
xforms_daysFromDateFunction(xmlXPathParserContextPtr ctxt,int nargs)338*b1cdbd2cSJim Jagielski void xforms_daysFromDateFunction(xmlXPathParserContextPtr ctxt, int nargs)
339*b1cdbd2cSJim Jagielski {
340*b1cdbd2cSJim Jagielski     // number of days from 1970-01-01 to supplied xsd:date(Time)
341*b1cdbd2cSJim Jagielski 
342*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
343*b1cdbd2cSJim Jagielski     xmlChar* pString = xmlXPathPopString(ctxt);
344*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
345*b1cdbd2cSJim Jagielski     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
346*b1cdbd2cSJim Jagielski 
347*b1cdbd2cSJim Jagielski     DateTime aDateTime;
348*b1cdbd2cSJim Jagielski     if (parseDateTime(aString, aDateTime))
349*b1cdbd2cSJim Jagielski     {
350*b1cdbd2cSJim Jagielski         Date aReferenceDate(1, 1, 1970);
351*b1cdbd2cSJim Jagielski         sal_Int32 nDays = aDateTime - aReferenceDate;
352*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, nDays);
353*b1cdbd2cSJim Jagielski     }
354*b1cdbd2cSJim Jagielski     else
355*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
356*b1cdbd2cSJim Jagielski 
357*b1cdbd2cSJim Jagielski 
358*b1cdbd2cSJim Jagielski }
359*b1cdbd2cSJim Jagielski 
360*b1cdbd2cSJim Jagielski 
xforms_secondsFromDateTimeFunction(xmlXPathParserContextPtr ctxt,int nargs)361*b1cdbd2cSJim Jagielski void xforms_secondsFromDateTimeFunction(xmlXPathParserContextPtr ctxt, int nargs)
362*b1cdbd2cSJim Jagielski {
363*b1cdbd2cSJim Jagielski     // number of seconds from 1970-01-01T00:00:00Z to supplied xsd:date(Time)
364*b1cdbd2cSJim Jagielski 
365*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
366*b1cdbd2cSJim Jagielski     xmlChar* pString = xmlXPathPopString(ctxt);
367*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
368*b1cdbd2cSJim Jagielski     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
369*b1cdbd2cSJim Jagielski 
370*b1cdbd2cSJim Jagielski     DateTime aDateTime;
371*b1cdbd2cSJim Jagielski 
372*b1cdbd2cSJim Jagielski     if (parseDateTime(aString, aDateTime))
373*b1cdbd2cSJim Jagielski     {
374*b1cdbd2cSJim Jagielski         Date aReferenceDate(1, 1, 1970);
375*b1cdbd2cSJim Jagielski         Time aReferenceTime(0, 0, 0);
376*b1cdbd2cSJim Jagielski         sal_Int32 nDays = aDateTime - aReferenceDate;
377*b1cdbd2cSJim Jagielski         sal_Int32 nSeconds = nDays * 24 * 60 * 60;
378*b1cdbd2cSJim Jagielski         nSeconds += aDateTime.GetHour() * 60 * 60;
379*b1cdbd2cSJim Jagielski         nSeconds += aDateTime.GetMin() * 60;
380*b1cdbd2cSJim Jagielski         nSeconds += aDateTime.GetSec();
381*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, nSeconds);
382*b1cdbd2cSJim Jagielski     }
383*b1cdbd2cSJim Jagielski     else
384*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
385*b1cdbd2cSJim Jagielski 
386*b1cdbd2cSJim Jagielski }
387*b1cdbd2cSJim Jagielski 
parseDuration(const xmlChar * aString,sal_Bool & bNegative,sal_Int32 & nYears,sal_Int32 & nMonth,sal_Int32 & nDays,sal_Int32 & nHours,sal_Int32 & nMinutes,sal_Int32 & nSeconds)388*b1cdbd2cSJim Jagielski static sal_Bool parseDuration(const xmlChar* aString, sal_Bool& bNegative, sal_Int32& nYears, sal_Int32& nMonth, sal_Int32& nDays,
389*b1cdbd2cSJim Jagielski                               sal_Int32& nHours, sal_Int32& nMinutes, sal_Int32& nSeconds)
390*b1cdbd2cSJim Jagielski {
391*b1cdbd2cSJim Jagielski     sal_Bool bTime = sal_False; // in part after T
392*b1cdbd2cSJim Jagielski     sal_Int32 nLength = strlen((char*)aString)+1;
393*b1cdbd2cSJim Jagielski     char *pString = (char*)rtl_allocateMemory(nLength);
394*b1cdbd2cSJim Jagielski     char *pString0 = pString;
395*b1cdbd2cSJim Jagielski     strncpy(pString, (char*)aString, nLength);
396*b1cdbd2cSJim Jagielski 
397*b1cdbd2cSJim Jagielski     if (pString[0] == '-') {
398*b1cdbd2cSJim Jagielski         bNegative = sal_True;
399*b1cdbd2cSJim Jagielski         pString++;
400*b1cdbd2cSJim Jagielski     }
401*b1cdbd2cSJim Jagielski 
402*b1cdbd2cSJim Jagielski     if (pString[0] != 'P')
403*b1cdbd2cSJim Jagielski         return sal_False;
404*b1cdbd2cSJim Jagielski     pString++;
405*b1cdbd2cSJim Jagielski     char* pToken = pString;
406*b1cdbd2cSJim Jagielski     while(pToken[0] != 0)
407*b1cdbd2cSJim Jagielski     {
408*b1cdbd2cSJim Jagielski         switch(pToken[0]) {
409*b1cdbd2cSJim Jagielski         case 'Y':
410*b1cdbd2cSJim Jagielski             pToken[0] = 0;
411*b1cdbd2cSJim Jagielski             nYears = atoi(pString);
412*b1cdbd2cSJim Jagielski             pString = ++pToken;
413*b1cdbd2cSJim Jagielski             break;
414*b1cdbd2cSJim Jagielski         case 'M':
415*b1cdbd2cSJim Jagielski             pToken[0] = 0;
416*b1cdbd2cSJim Jagielski             if (!bTime)
417*b1cdbd2cSJim Jagielski                 nMonth = atoi(pString);
418*b1cdbd2cSJim Jagielski             else
419*b1cdbd2cSJim Jagielski                 nMinutes = atoi(pString);
420*b1cdbd2cSJim Jagielski             pString = ++pToken;
421*b1cdbd2cSJim Jagielski             break;
422*b1cdbd2cSJim Jagielski         case 'D':
423*b1cdbd2cSJim Jagielski             pToken[0] = 0;
424*b1cdbd2cSJim Jagielski             nDays = atoi(pString);
425*b1cdbd2cSJim Jagielski             pString = ++pToken;
426*b1cdbd2cSJim Jagielski             break;
427*b1cdbd2cSJim Jagielski         case 'H':
428*b1cdbd2cSJim Jagielski             pToken[0] = 0;
429*b1cdbd2cSJim Jagielski             nHours = atoi(pString);
430*b1cdbd2cSJim Jagielski             pString = ++pToken;
431*b1cdbd2cSJim Jagielski             break;
432*b1cdbd2cSJim Jagielski         case 'S':
433*b1cdbd2cSJim Jagielski             pToken[0] = 0;
434*b1cdbd2cSJim Jagielski             nSeconds = atoi(pString);
435*b1cdbd2cSJim Jagielski             pString = ++pToken;
436*b1cdbd2cSJim Jagielski             break;
437*b1cdbd2cSJim Jagielski         case 'T':
438*b1cdbd2cSJim Jagielski             bTime = sal_True;
439*b1cdbd2cSJim Jagielski             pString = ++pToken;
440*b1cdbd2cSJim Jagielski             break;
441*b1cdbd2cSJim Jagielski         default:
442*b1cdbd2cSJim Jagielski             pToken++;
443*b1cdbd2cSJim Jagielski         }
444*b1cdbd2cSJim Jagielski     }
445*b1cdbd2cSJim Jagielski     rtl_freeMemory(pString0);
446*b1cdbd2cSJim Jagielski     return sal_True;
447*b1cdbd2cSJim Jagielski }
448*b1cdbd2cSJim Jagielski 
xforms_secondsFuction(xmlXPathParserContextPtr ctxt,int nargs)449*b1cdbd2cSJim Jagielski void xforms_secondsFuction(xmlXPathParserContextPtr ctxt, int nargs)
450*b1cdbd2cSJim Jagielski {
451*b1cdbd2cSJim Jagielski     // convert a xsd:duration to seconds
452*b1cdbd2cSJim Jagielski     // (-)PnYnMnDTnHnMnS
453*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
454*b1cdbd2cSJim Jagielski     xmlChar* pString = xmlXPathPopString(ctxt);
455*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
456*b1cdbd2cSJim Jagielski 
457*b1cdbd2cSJim Jagielski     sal_Bool bNegative = sal_False;
458*b1cdbd2cSJim Jagielski     sal_Int32 nYears = 0;
459*b1cdbd2cSJim Jagielski     sal_Int32 nMonths = 0;
460*b1cdbd2cSJim Jagielski     sal_Int32 nDays = 0;
461*b1cdbd2cSJim Jagielski     sal_Int32 nHours = 0;
462*b1cdbd2cSJim Jagielski     sal_Int32 nMinutes = 0;
463*b1cdbd2cSJim Jagielski     sal_Int32 nSeconds = 0;
464*b1cdbd2cSJim Jagielski 
465*b1cdbd2cSJim Jagielski     if (parseDuration(pString, bNegative, nYears, nMonths, nDays, nHours, nMinutes, nSeconds))
466*b1cdbd2cSJim Jagielski     {
467*b1cdbd2cSJim Jagielski         nSeconds += nMinutes*60;
468*b1cdbd2cSJim Jagielski         nSeconds += nHours*60*60;
469*b1cdbd2cSJim Jagielski         nSeconds += nDays*24*60*60;
470*b1cdbd2cSJim Jagielski         // year and month are ignored according to spec
471*b1cdbd2cSJim Jagielski         if (bNegative)
472*b1cdbd2cSJim Jagielski             nSeconds = 0 - nSeconds;
473*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, nSeconds);
474*b1cdbd2cSJim Jagielski     }
475*b1cdbd2cSJim Jagielski     else
476*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
477*b1cdbd2cSJim Jagielski }
478*b1cdbd2cSJim Jagielski 
xforms_monthsFuction(xmlXPathParserContextPtr ctxt,int nargs)479*b1cdbd2cSJim Jagielski void xforms_monthsFuction(xmlXPathParserContextPtr ctxt, int nargs)
480*b1cdbd2cSJim Jagielski {
481*b1cdbd2cSJim Jagielski     // convert a xsd:duration to seconds
482*b1cdbd2cSJim Jagielski     // (-)PnYnMnDTnHnMnS
483*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
484*b1cdbd2cSJim Jagielski     xmlChar* pString = xmlXPathPopString(ctxt);
485*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
486*b1cdbd2cSJim Jagielski 
487*b1cdbd2cSJim Jagielski     sal_Bool bNegative = sal_False;
488*b1cdbd2cSJim Jagielski     sal_Int32 nYears = 0;
489*b1cdbd2cSJim Jagielski     sal_Int32 nMonths = 0;
490*b1cdbd2cSJim Jagielski     sal_Int32 nDays = 0;
491*b1cdbd2cSJim Jagielski     sal_Int32 nHours = 0;
492*b1cdbd2cSJim Jagielski     sal_Int32 nMinutes = 0;
493*b1cdbd2cSJim Jagielski     sal_Int32 nSeconds = 0;
494*b1cdbd2cSJim Jagielski 
495*b1cdbd2cSJim Jagielski     if (parseDuration(pString, bNegative, nYears, nMonths, nDays, nHours, nMinutes, nSeconds))
496*b1cdbd2cSJim Jagielski     {
497*b1cdbd2cSJim Jagielski         nMonths += nYears*12;
498*b1cdbd2cSJim Jagielski         // Days, Houres, Minutes and seconds are ignored, see spec
499*b1cdbd2cSJim Jagielski         if (bNegative)
500*b1cdbd2cSJim Jagielski             nMonths = 0 - nMonths;
501*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, nMonths);
502*b1cdbd2cSJim Jagielski     }
503*b1cdbd2cSJim Jagielski     else
504*b1cdbd2cSJim Jagielski         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
505*b1cdbd2cSJim Jagielski 
506*b1cdbd2cSJim Jagielski }
507*b1cdbd2cSJim Jagielski 
508*b1cdbd2cSJim Jagielski // Node-set Functions
xforms_instanceFuction(xmlXPathParserContextPtr ctxt,int nargs)509*b1cdbd2cSJim Jagielski void xforms_instanceFuction(xmlXPathParserContextPtr ctxt, int nargs)
510*b1cdbd2cSJim Jagielski {
511*b1cdbd2cSJim Jagielski     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
512*b1cdbd2cSJim Jagielski     xmlChar *pString = xmlXPathPopString(ctxt);
513*b1cdbd2cSJim Jagielski     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
514*b1cdbd2cSJim Jagielski     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
515*b1cdbd2cSJim Jagielski 
516*b1cdbd2cSJim Jagielski     Reference< XModel > aModel = ((CLibxml2XFormsExtension*)ctxt->context->funcLookupData)->getModel();
517*b1cdbd2cSJim Jagielski     if (aModel.is())
518*b1cdbd2cSJim Jagielski     {
519*b1cdbd2cSJim Jagielski         Reference< XDocument > aInstance = aModel->getInstanceDocument(aString);
520*b1cdbd2cSJim Jagielski         if (aInstance.is())
521*b1cdbd2cSJim Jagielski         {
522*b1cdbd2cSJim Jagielski             try {
523*b1cdbd2cSJim Jagielski                 // xmlXPathObjectPtr xmlXPathNewNodeSet        (xmlNodePtr val);
524*b1cdbd2cSJim Jagielski                 Reference< XUnoTunnel > aTunnel(aInstance, UNO_QUERY_THROW);
525*b1cdbd2cSJim Jagielski                 xmlNodePtr pNode = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(Sequence< sal_Int8 >()) );
526*b1cdbd2cSJim Jagielski                 xmlXPathObjectPtr pObject = xmlXPathNewNodeSet(pNode);
527*b1cdbd2cSJim Jagielski                 xmlXPathReturnNodeSet(ctxt, pObject->nodesetval);
528*b1cdbd2cSJim Jagielski             } catch (RuntimeException&)
529*b1cdbd2cSJim Jagielski             {
530*b1cdbd2cSJim Jagielski                 xmlXPathReturnEmptyNodeSet(ctxt);
531*b1cdbd2cSJim Jagielski             }
532*b1cdbd2cSJim Jagielski         }
533*b1cdbd2cSJim Jagielski         else
534*b1cdbd2cSJim Jagielski             xmlXPathReturnEmptyNodeSet(ctxt);
535*b1cdbd2cSJim Jagielski     }
536*b1cdbd2cSJim Jagielski     else
537*b1cdbd2cSJim Jagielski         xmlXPathReturnEmptyNodeSet(ctxt);
538*b1cdbd2cSJim Jagielski 
539*b1cdbd2cSJim Jagielski }
540*b1cdbd2cSJim Jagielski 
541*b1cdbd2cSJim Jagielski // Node-set Functions, XForms 1.1
xforms_currentFunction(xmlXPathParserContextPtr ctxt,int nargs)542*b1cdbd2cSJim Jagielski void xforms_currentFunction(xmlXPathParserContextPtr ctxt, int nargs)
543*b1cdbd2cSJim Jagielski {
544*b1cdbd2cSJim Jagielski     if (nargs != 0) XP_ERROR(XPATH_INVALID_ARITY);
545*b1cdbd2cSJim Jagielski 
546*b1cdbd2cSJim Jagielski     Reference< XNode > aNode = ((CLibxml2XFormsExtension*)ctxt->context->funcLookupData)->getContextNode();
547*b1cdbd2cSJim Jagielski 
548*b1cdbd2cSJim Jagielski     if (aNode.is())
549*b1cdbd2cSJim Jagielski     {
550*b1cdbd2cSJim Jagielski         try {
551*b1cdbd2cSJim Jagielski             Reference< XUnoTunnel > aTunnel(aNode, UNO_QUERY_THROW);
552*b1cdbd2cSJim Jagielski             xmlNodePtr pNode = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(Sequence< sal_Int8 >()) );
553*b1cdbd2cSJim Jagielski             xmlXPathObjectPtr pObject = xmlXPathNewNodeSet(pNode);
554*b1cdbd2cSJim Jagielski             xmlXPathReturnNodeSet(ctxt, pObject->nodesetval);
555*b1cdbd2cSJim Jagielski         }
556*b1cdbd2cSJim Jagielski         catch (RuntimeException&)
557*b1cdbd2cSJim Jagielski         {
558*b1cdbd2cSJim Jagielski             xmlXPathReturnEmptyNodeSet(ctxt);
559*b1cdbd2cSJim Jagielski         }
560*b1cdbd2cSJim Jagielski     }
561*b1cdbd2cSJim Jagielski     else
562*b1cdbd2cSJim Jagielski         xmlXPathReturnEmptyNodeSet(ctxt);
563*b1cdbd2cSJim Jagielski }
564