private QilNode CompileSingleKey(List <Key> defList, QilNode key, IFocus env) { Debug.Assert(defList != null && defList.Count > 0); if (defList.Count == 1) { return(_f.Invoke(defList[0].Function, _f.ActualParameterList(env.GetCurrent(), key))); } QilIterator i = _f.Let(key); QilNode result = _f.Sequence(); foreach (Key keyDef in defList) { result.Add(_f.Invoke(keyDef.Function, _f.ActualParameterList(env.GetCurrent(), i))); } return(_f.Loop(i, result)); }
QilNode IXPathEnvironment.ResolveFunction(string prefix, string name, IList <QilNode> args, IFocus env) { Debug.Assert(!args.IsReadOnly, "Writable collection expected"); if (prefix.Length == 0) { FunctionInfo?func; if (FunctionTable.TryGetValue(name, out func)) { func.CastArguments(args, name, _f); switch (func.id) { case FuncId.Current: if (!_allowCurrent) { throw new XslLoadException(SR.Xslt_CurrentNotAllowed); } // NOTE: This is the only place where the current node (and not the context node) must be used return(((IXPathEnvironment)this).GetCurrent() !); case FuncId.Key: if (!_allowKey) { throw new XslLoadException(SR.Xslt_KeyNotAllowed); } return(CompileFnKey(args[0], args[1], env)); case FuncId.Document: return(CompileFnDocument(args[0], args.Count > 1 ? args[1] : null)); case FuncId.FormatNumber: return(CompileFormatNumber(args[0], args[1], args.Count > 2 ? args[2] : null)); case FuncId.UnparsedEntityUri: return(CompileUnparsedEntityUri(args[0])); case FuncId.GenerateId: return(CompileGenerateId(args.Count > 0 ? args[0] : env.GetCurrent() !)); case FuncId.SystemProperty: return(CompileSystemProperty(args[0])); case FuncId.ElementAvailable: return(CompileElementAvailable(args[0])); case FuncId.FunctionAvailable: return(CompileFunctionAvailable(args[0])); default: Debug.Fail($"{func.id} is present in the function table, but absent from the switch"); return(null); } } else { throw new XslLoadException(SR.Xslt_UnknownXsltFunction, Compiler.ConstructQName(prefix, name)); } } else { string ns = ResolvePrefixThrow(/*ignoreDefaultNs:*/ true, prefix); Debug.Assert(ns != null); if (ns == XmlReservedNs.NsMsxsl) { if (name == "node-set") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(CompileMsNodeSet(args[0])); } else if (name == "string-compare") { FunctionInfo.CheckArity(/*minArg:*/ 2, /*maxArg:*/ 4, name, args.Count); return(_f.InvokeMsStringCompare( /*x: */ _f.ConvertToString(args[0]), /*y: */ _f.ConvertToString(args[1]), /*lang: */ 2 < args.Count ? _f.ConvertToString(args[2]) : _f.String(string.Empty), /*options:*/ 3 < args.Count ? _f.ConvertToString(args[3]) : _f.String(string.Empty) )); } else if (name == "utc") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(_f.InvokeMsUtc(/*datetime:*/ _f.ConvertToString(args[0]))); } else if (name == "format-date" || name == "format-time") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 3, name, args.Count); return(_f.InvokeMsFormatDateTime( /*datetime:*/ _f.ConvertToString(args[0]), /*format: */ 1 < args.Count ? _f.ConvertToString(args[1]) : _f.String(string.Empty), /*lang: */ 2 < args.Count ? _f.ConvertToString(args[2]) : _f.String(string.Empty), /*isDate: */ _f.Boolean(name == "format-date") )); } else if (name == "local-name") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(_f.InvokeMsLocalName(_f.ConvertToString(args[0]))); } else if (name == "namespace-uri") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(_f.InvokeMsNamespaceUri(_f.ConvertToString(args[0]), env.GetCurrent() !)); } else if (name == "number") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(_f.InvokeMsNumber(args[0])); } } if (ns == XmlReservedNs.NsExsltCommon) { if (name == "node-set") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(CompileMsNodeSet(args[0])); } else if (name == "object-type") { FunctionInfo.CheckArity(/*minArg:*/ 1, /*maxArg:*/ 1, name, args.Count); return(EXslObjectType(args[0])); } } // NOTE: If you add any function here, add it to IsFunctionAvailable as well // Ensure that all node-set parameters are DocOrderDistinct for (int i = 0; i < args.Count; i++) { args[i] = _f.SafeDocOrderDistinct(args[i]); } if (_compiler.Settings.EnableScript) { XmlExtensionFunction?scrFunc = _compiler.Scripts.ResolveFunction(name, ns, args.Count, (IErrorHelper)this); if (scrFunc != null) { return(GenerateScriptCall(_f.QName(name, ns, prefix), scrFunc, args)); } } else { if (_compiler.Scripts.ScriptClasses.ContainsKey(ns)) { ReportWarning(SR.Xslt_ScriptsProhibited); return(_f.Error(_lastScope !.SourceLine, SR.Xslt_ScriptsProhibited)); } } return(_f.XsltInvokeLateBound(_f.QName(name, ns, prefix), args)); } }
private QilNode CompileSingleKey(QilNode name, QilNode key, IFocus env) { Debug.Assert(name.XmlType == T.StringX && key.XmlType == T.StringX); QilNode result; if (name.NodeType == QilNodeType.LiteralString) { string keyName = (QilLiteral)name; _compiler.ParseQName(keyName, out string prefix, out string local, default(ThrowErrorHelper)); string nsUri = ResolvePrefixThrow(/*ignoreDefaultNs:*/ true, prefix); QilName qname = _f.QName(local, nsUri, prefix); if (!_compiler.Keys.Contains(qname)) { throw new XslLoadException(SR.Xslt_UndefinedKey, keyName); } result = CompileSingleKey(_compiler.Keys[qname], key, env); } else { if (_generalKey == null) { _generalKey = CreateGeneralKeyFunction(); } QilIterator i = _f.Let(name); QilNode resolvedName = ResolveQNameDynamic(/*ignoreDefaultNs:*/ true, i); result = _f.Invoke(_generalKey, _f.ActualParameterList(i, resolvedName, key, env.GetCurrent())); result = _f.Loop(i, result); } return(result); }
// NOTE: DO NOT call QilNode.Clone() while executing this method since fixup nodes cannot be cloned QilNode IXPathEnvironment.ResolveFunction(string prefix, string name, IList<QilNode> args, IFocus env) { Debug.Assert(!args.IsReadOnly, "Writable collection expected"); if (prefix.Length == 0) { FunctionInfo func; if (FunctionTable.TryGetValue(name, out func)) { func.CastArguments(args, name, f); switch (func.id) { case FuncId.Current : if (!allowCurrent) { throw new XslLoadException(Res.Xslt_CurrentNotAllowed); } // NOTE: This is the only place where the current node (and not the context node) must be used return ((IXPathEnvironment) this).GetCurrent(); case FuncId.Key : if (!allowKey) { throw new XslLoadException(Res.Xslt_KeyNotAllowed); } return CompileFnKey(args[0], args[1], env); case FuncId.Document : return CompileFnDocument(args[0], args.Count > 1 ? args[1] : null); case FuncId.FormatNumber : return CompileFormatNumber(args[0], args[1], args.Count > 2 ? args[2] : null); case FuncId.UnparsedEntityUri : return CompileUnparsedEntityUri(args[0]); case FuncId.GenerateId : return CompileGenerateId(args.Count > 0 ? args[0] : env.GetCurrent()); case FuncId.SystemProperty : return CompileSystemProperty(args[0]); case FuncId.ElementAvailable : return CompileElementAvailable(args[0]); case FuncId.FunctionAvailable : return CompileFunctionAvailable(args[0]); default: Debug.Fail(func.id + " is present in the function table, but absent from the switch"); return null; } } else { throw new XslLoadException(Res.Xslt_UnknownXsltFunction, Compiler.ConstructQName(prefix, name)); } } else { string ns = ResolvePrefixThrow(/*ignoreDefaultNs:*/true, prefix); Debug.Assert(ns != null); if (ns == XmlReservedNs.NsMsxsl) { if (name == "node-set") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return CompileMsNodeSet(args[0]); } else if (name == "string-compare") { FunctionInfo.CheckArity(/*minArg:*/2, /*maxArg:*/4, name, args.Count); return f.InvokeMsStringCompare( /*x: */f.ConvertToString(args[0]), /*y: */f.ConvertToString(args[1]), /*lang: */2 < args.Count ? f.ConvertToString(args[2]) : f.String(string.Empty), /*options:*/3 < args.Count ? f.ConvertToString(args[3]) : f.String(string.Empty) ); } else if (name == "utc") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return f.InvokeMsUtc(/*datetime:*/f.ConvertToString(args[0])); } else if (name == "format-date" || name == "format-time") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/3, name, args.Count); bool fwdCompat = (xslVersion == XslVersion.ForwardsCompatible); return f.InvokeMsFormatDateTime( /*datetime:*/f.ConvertToString(args[0]), /*format: */1 < args.Count ? f.ConvertToString(args[1]) : f.String(string.Empty), /*lang: */2 < args.Count ? f.ConvertToString(args[2]) : f.String(string.Empty), /*isDate: */f.Boolean(name == "format-date") ); } else if (name == "local-name") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return f.InvokeMsLocalName(f.ConvertToString(args[0])); } else if (name == "namespace-uri") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return f.InvokeMsNamespaceUri(f.ConvertToString(args[0]), env.GetCurrent()); } else if (name == "number") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return f.InvokeMsNumber(args[0]); } } if (ns == XmlReservedNs.NsExsltCommon) { if (name == "node-set") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return CompileMsNodeSet(args[0]); } else if (name == "object-type") { FunctionInfo.CheckArity(/*minArg:*/1, /*maxArg:*/1, name, args.Count); return EXslObjectType(args[0]); } } // NOTE: If you add any function here, add it to IsFunctionAvailable as well // Ensure that all node-set parameters are DocOrderDistinct for (int i = 0; i < args.Count; i++) args[i] = f.SafeDocOrderDistinct(args[i]); if (compiler.Settings.EnableScript) { XmlExtensionFunction scrFunc = compiler.Scripts.ResolveFunction(name, ns, args.Count, (IErrorHelper)this); if (scrFunc != null) { return GenerateScriptCall(f.QName(name, ns, prefix), scrFunc, args); } } else { if (compiler.Scripts.ScriptClasses.ContainsKey(ns)) { ReportWarning(Res.Xslt_ScriptsProhibited); return f.Error(lastScope.SourceLine, Res.Xslt_ScriptsProhibited); } } return f.XsltInvokeLateBound(f.QName(name, ns, prefix), args); } }
private QilNode CompileSingleKey(List<Key> defList, QilNode key, IFocus env) { Debug.Assert(defList != null && defList.Count > 0); if (defList.Count == 1) { return f.Invoke(defList[0].Function, f.ActualParameterList(env.GetCurrent(), key)); } QilIterator i = f.Let(key); QilNode result = f.Sequence(); foreach (Key keyDef in defList) { result.Add(f.Invoke(keyDef.Function, f.ActualParameterList(env.GetCurrent(), i))); } return f.Loop(i, result); }
private QilNode CompileSingleKey(QilNode name, QilNode key, IFocus env) { Debug.Assert(name.XmlType == T.StringX && key.XmlType == T.StringX); QilNode result; if (name.NodeType == QilNodeType.LiteralString) { string keyName = (string)(QilLiteral)name; string prefix, local, nsUri; compiler.ParseQName(keyName, out prefix, out local, new ThrowErrorHelper()); nsUri = ResolvePrefixThrow(/*ignoreDefaultNs:*/true, prefix); QilName qname = f.QName(local, nsUri, prefix); if (!compiler.Keys.Contains(qname)) { throw new XslLoadException(Res.Xslt_UndefinedKey, keyName); } result = CompileSingleKey(compiler.Keys[qname], key, env); } else { if (generalKey == null) { generalKey = CreateGeneralKeyFunction(); } QilIterator i = f.Let(name); QilNode resolvedName = ResolveQNameDynamic(/*ignoreDefaultNs:*/true, i); result = f.Invoke(generalKey, f.ActualParameterList(i, resolvedName, key, env.GetCurrent())); result = f.Loop(i, result); } return result; }