Ejemplo n.º 1
0
        public QilNode BuildMatcher(QilIterator it, IList <XslNode> actualArgs, QilNode otherwise)
        {
            QilNode result = otherwise;

            foreach (List <TemplateMatch> list in allMatches)
            {
                foreach (TemplateMatch match in list)
                {
                    XmlNodeKindFlags nodeKind = match.NodeKind;
                    QilName          qname    = match.QName;
                    QilNode          cond     = match.Condition;

                    if (cond != null)
                    {
                        // We have to clone, because the same pattern may be used
                        // in many different xsl:apply-templates/imports functions
                        cond = cond.DeepClone(f.BaseFactory);
                        cond = refReplacer.Replace(cond, match.Iterator, it);
                    }

                    if (nodeKind != 0)
                    {
                        XmlQueryType nodeType;
                        switch (nodeKind)
                        {
                        case XmlNodeKindFlags.Element: nodeType = T.Element;  break;

                        case XmlNodeKindFlags.Attribute: nodeType = T.Attribute;  break;

                        case XmlNodeKindFlags.Text: nodeType = T.Text;  break;

                        case XmlNodeKindFlags.Document: nodeType = T.Document;  break;

                        case XmlNodeKindFlags.Comment: nodeType = T.Comment;  break;

                        case XmlNodeKindFlags.PI: nodeType = T.PI;  break;

                        default: nodeType = null;  break;
                        }

                        Debug.Assert(nodeType != null, "Unexpected nodeKind: " + nodeKind);
                        QilNode typeNameCheck = f.IsType(it, nodeType);

                        if (qname != null)
                        {
                            typeNameCheck = f.And(typeNameCheck, f.Eq(f.NameOf(it), qname.ShallowClone(f.BaseFactory)));
                        }

                        cond = (cond == null) ? typeNameCheck : f.And(typeNameCheck, cond);
                    }

                    result = f.Conditional(cond,
                                           invkGen.GenerateInvoke(match.TemplateFunction, actualArgs),
                                           result
                                           );
                }
            }
            return(result);
        }
Ejemplo n.º 2
0
        //The structure of result is a Filter, variable is current node, body is the match condition.
        //Previous predicate build logic in XPathPatternBuilder is match from right to left, which have 2^n complexiy when have lots of position predicates. TFS #368771
        //Now change the logic to: If predicates contains position/last predicates, given the current node, filter out all the nodes that match the predicates,
        //and then check if current node is in the result set.
        public QilNode BuildPredicates(QilNode nodeset, List <QilNode> predicates)
        {
            //convert predicates to boolean type
            List <QilNode> convertedPredicates = new List <QilNode>(predicates.Count);

            foreach (var predicate in predicates)
            {
                convertedPredicates.Add(XPathBuilder.PredicateToBoolean(predicate, _f, _predicateEnvironment));
            }

            QilLoop     nodeFilter = (QilLoop)nodeset;
            QilIterator current    = nodeFilter.Variable;

            //If no last() and position() in predicates, use nodeFilter.Variable to fixup current
            //because all the predicates only based on the input variable, no matter what other predicates are.
            if (_predicateEnvironment.numFixupLast == 0 && _predicateEnvironment.numFixupPosition == 0)
            {
                foreach (var predicate in convertedPredicates)
                {
                    nodeFilter.Body = _f.And(nodeFilter.Body, predicate);
                }
                nodeFilter.Body = _predicateEnvironment.fixupVisitor.Fixup(nodeFilter.Body, current, null);
            }
            //If any preidcate contains last() or position() node, then the current node is based on previous predicates,
            //for instance, a[...][2] is match second node after filter 'a[...]' instead of second 'a'.
            else
            {
                //filter out the siblings
                QilIterator parentIter = _f.For(_f.Parent(current));
                QilNode     sibling    = _f.Content(parentIter);
                //generate filter based on input filter
                QilLoop siblingFilter = (QilLoop)nodeset.DeepClone(_f.BaseFactory);
                siblingFilter.Variable.Binding = sibling;
                siblingFilter = (QilLoop)_f.Loop(parentIter, siblingFilter);

                //build predicates from left to right to get all the matching nodes
                QilNode matchingSet = siblingFilter;
                foreach (var predicate in convertedPredicates)
                {
                    matchingSet = XPathBuilder.BuildOnePredicate(matchingSet, predicate, /*isReverseStep*/ false,
                                                                 _f, _predicateEnvironment.fixupVisitor,
                                                                 ref _predicateEnvironment.numFixupCurrent, ref _predicateEnvironment.numFixupPosition, ref _predicateEnvironment.numFixupLast);
                }

                //check if the matching nodes contains the current node
                QilIterator matchNodeIter = _f.For(matchingSet);
                QilNode     filterCurrent = _f.Filter(matchNodeIter, _f.Is(matchNodeIter, current));
                nodeFilter.Body = _f.Not(_f.IsEmpty(filterCurrent));
                //for passing type check, explicit say the result is target type
                nodeFilter.Body = _f.And(_f.IsType(current, nodeFilter.XmlType), nodeFilter.Body);
            }

            SetPriority(nodeset, 0.5);
            return(nodeset);
        }
Ejemplo n.º 3
0
        private QilNode MatchPattern(QilIterator it, TemplateMatch match)
        {
            QilNode cond = match.Condition;

            if (cond == null)
            {
                return(_f.True());
            }
            else
            {
                // We have to clone, because the same pattern may be used
                // in many different xsl:apply-templates/imports functions
                cond = cond.DeepClone(_f.BaseFactory);
                return(_refReplacer.Replace(cond, match.Iterator, it));
            }
        }
Ejemplo n.º 4
0
        private QilNode PlaceMarker(QilNode countPattern, QilNode fromPattern, bool multiple)
        {
            /*
                Quotation from XSLT 2.0 spec:
                * Let $A be the node sequence selected by the expression
                    ancestor-or-self::node()[matches-count(.)]          (level = "multiple")
                    ancestor-or-self::node()[matches-count(.)][1]       (level = "single")
                * Let $F be the node sequence selected by the expression
                    ancestor-or-self::node()[matches-from(.)][1]
                * Let $AF be the value of
                    $A intersect ($F/descendant-or-self::node())
                * Return the result of the expression
                    for $af in $AF return 1+count($af/preceding-sibling::node()[matches-count(.)])

                NOTE: There are some distinctions between XSLT 1.0 and XSLT 2.0 specs. In our 1.0 implementation we:
                1) Assume that the 'matches-from()' function does not match root nodes by default.
                2) Instead of '$A intersect ($F/descendant-or-self::node())' (which, by the way,
                   would filter out attribute and namespace nodes from $A) we calculate
                     '$A'           if the 'from' attribute is omitted,
                     '$A[. >> $F]'  if the 'from' attribute is present.
            */

            QilNode countPattern2, countMatches, fromMatches, A, F, AF;
            QilIterator i, j;

            countPattern2 = (countPattern != null) ? countPattern.DeepClone(_f.BaseFactory) : null;
            countMatches = _f.Filter(i = _f.For(_f.AncestorOrSelf(GetCurrentNode())), MatchCountPattern(countPattern, i));
            if (multiple)
            {
                A = _f.DocOrderDistinct(countMatches);
            }
            else
            {
                A = _f.Filter(i = _f.For(countMatches), _f.Eq(_f.PositionOf(i), _f.Int32(1)));
            }

            if (fromPattern == null)
            {
                AF = A;
            }
            else
            {
                fromMatches = _f.Filter(i = _f.For(_f.AncestorOrSelf(GetCurrentNode())), MatchPattern(fromPattern, i));
                F = _f.Filter(i = _f.For(fromMatches), _f.Eq(_f.PositionOf(i), _f.Int32(1)));
                AF = _f.Loop(i = _f.For(F), _f.Filter(j = _f.For(A), _f.Before(i, j)));
            }

            return _f.Loop(j = _f.For(AF),
                _f.Add(_f.Int32(1), _f.Length(_f.Filter(i = _f.For(_f.PrecedingSibling(j)), MatchCountPattern(countPattern2, i))))
            );
        }
Ejemplo n.º 5
0
        private void CompileDataTypeAttribute(string attValue, bool fwdCompat, ref QilNode select, out QilNode select2)
        {
            const string DtText = "text";
            const string DtNumber = "number";
            QilNode result = CompileStringAvt(attValue);
            if (result != null)
            {
                if (result.NodeType == QilNodeType.LiteralString)
                {
                    string dataType = (string)(QilLiteral)result;
                    if (dataType == DtNumber)
                    {
                        select = _f.ConvertToNumber(select);
                        select2 = null;
                        return;
                    }
                    else if (dataType == DtText)
                    {
                        // fall through to default case
                    }
                    else
                    {
                        if (!fwdCompat)
                        {
                            // check for qname-but-not-ncname
                            string prefix, local, nsUri;
                            bool isValid = _compiler.ParseQName(dataType, out prefix, out local, (IErrorHelper)this);
                            nsUri = isValid ? ResolvePrefix(/*ignoreDefaultNs:*/true, prefix) : _compiler.CreatePhantomNamespace();

                            if (nsUri.Length == 0)
                            {
                                // this is a ncname; we might report SR.Xslt_InvalidAttrValue,
                                // but the following error message is more user friendly
                            }
                            ReportError(/*[XT_034]*/SR.Xslt_BistateAttribute, "data-type", DtText, DtNumber);
                        }
                        // fall through to default case
                    }
                }
                else
                {
                    // Precalculate its value outside of for-each loop
                    QilIterator dt, qname;

                    result = _f.Loop(dt = _f.Let(result),
                        _f.Conditional(_f.Eq(dt, _f.String(DtNumber)), _f.False(),
                        _f.Conditional(_f.Eq(dt, _f.String(DtText)), _f.True(),
                        fwdCompat ? _f.True() :
                        _f.Loop(qname = _f.Let(ResolveQNameDynamic(/*ignoreDefaultNs:*/true, dt)),
                            _f.Error(_lastScope.SourceLine,
                                SR.Xslt_BistateAttribute, "data-type", DtText, DtNumber
                            )
                        )
                    )));

                    QilIterator text = _f.Let(result);
                    _varHelper.AddVariable(text);

                    // Make two sort keys since heterogenous sort keys are not allowed
                    select2 = select.DeepClone(_f.BaseFactory);
                    select = _f.Conditional(text, _f.ConvertToString(select), _f.String(string.Empty));
                    select2 = _f.Conditional(text, _f.Double(0), _f.ConvertToNumber(select2));
                    return;
                }
            }

            // Default case
            select = _f.ConvertToString(select);
            select2 = null;
        }