2 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright (C) 2006, 2009 Apple Inc.
4 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "core/xml/XPathPath.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/NodeTraversal.h"
33 #include "core/xml/XPathPredicate.h"
34 #include "core/xml/XPathStep.h"
35 #include "core/xml/XPathValue.h"
40 Filter::Filter(Expression
* expr
, HeapVector
<Member
<Predicate
>>& predicates
)
43 m_predicates
.swap(predicates
);
44 setIsContextNodeSensitive(m_expr
->isContextNodeSensitive());
45 setIsContextPositionSensitive(m_expr
->isContextPositionSensitive());
46 setIsContextSizeSensitive(m_expr
->isContextSizeSensitive());
55 visitor
->trace(m_expr
);
56 visitor
->trace(m_predicates
);
57 Expression::trace(visitor
);
60 Value
Filter::evaluate(EvaluationContext
& evaluationContext
) const
62 Value v
= m_expr
->evaluate(evaluationContext
);
64 NodeSet
& nodes
= v
.modifiableNodeSet(evaluationContext
);
67 for (unsigned i
= 0; i
< m_predicates
.size(); i
++) {
68 NodeSet
* newNodes
= NodeSet::create();
69 evaluationContext
.size
= nodes
.size();
70 evaluationContext
.position
= 0;
72 for (unsigned j
= 0; j
< nodes
.size(); j
++) {
73 Node
* node
= nodes
[j
];
75 evaluationContext
.node
= node
;
76 ++evaluationContext
.position
;
78 if (m_predicates
[i
]->evaluate(evaluationContext
))
79 newNodes
->append(node
);
81 nodes
.swap(*newNodes
);
87 LocationPath::LocationPath()
90 setIsContextNodeSensitive(true);
93 LocationPath::~LocationPath()
97 DEFINE_TRACE(LocationPath
)
99 visitor
->trace(m_steps
);
100 Expression::trace(visitor
);
103 Value
LocationPath::evaluate(EvaluationContext
& evaluationContext
) const
105 EvaluationContext clonedContext
= evaluationContext
;
106 // http://www.w3.org/TR/xpath/
107 // Section 2, Location Paths:
108 // "/ selects the document root (which is always the parent of the document element)"
109 // "A / by itself selects the root node of the document containing the context node."
110 // In the case of a tree that is detached from the document, we violate
111 // the spec and treat / as the root node of the detached tree.
112 // This is for compatibility with Firefox, and also seems like a more
113 // logical treatment of where you would expect the "root" to be.
114 Node
* context
= evaluationContext
.node
.get();
115 if (m_absolute
&& context
->nodeType() != Node::DOCUMENT_NODE
) {
116 if (context
->inDocument())
117 context
= context
->ownerDocument();
119 context
= &NodeTraversal::highestAncestorOrSelf(*context
);
122 NodeSet
* nodes
= NodeSet::create();
123 nodes
->append(context
);
124 evaluate(clonedContext
, *nodes
);
126 return Value(nodes
, Value::adopt
);
129 void LocationPath::evaluate(EvaluationContext
& context
, NodeSet
& nodes
) const
131 bool resultIsSorted
= nodes
.isSorted();
133 for (unsigned i
= 0; i
< m_steps
.size(); i
++) {
134 Step
* step
= m_steps
[i
];
135 NodeSet
* newNodes
= NodeSet::create();
136 WillBeHeapHashSet
<RawPtrWillBeMember
<Node
>> newNodesSet
;
138 bool needToCheckForDuplicateNodes
= !nodes
.subtreesAreDisjoint() || (step
->axis() != Step::ChildAxis
&& step
->axis() != Step::SelfAxis
139 && step
->axis() != Step::DescendantAxis
&& step
->axis() != Step::DescendantOrSelfAxis
&& step
->axis() != Step::AttributeAxis
);
141 if (needToCheckForDuplicateNodes
)
142 resultIsSorted
= false;
144 // This is a simplified check that can be improved to handle more cases.
145 if (nodes
.subtreesAreDisjoint() && (step
->axis() == Step::ChildAxis
|| step
->axis() == Step::SelfAxis
))
146 newNodes
->markSubtreesDisjoint(true);
148 for (unsigned j
= 0; j
< nodes
.size(); j
++) {
149 NodeSet
* matches
= NodeSet::create();
150 step
->evaluate(context
, nodes
[j
], *matches
);
152 if (!matches
->isSorted())
153 resultIsSorted
= false;
155 for (size_t nodeIndex
= 0; nodeIndex
< matches
->size(); ++nodeIndex
) {
156 Node
* node
= (*matches
)[nodeIndex
];
157 if (!needToCheckForDuplicateNodes
|| newNodesSet
.add(node
).isNewEntry
)
158 newNodes
->append(node
);
162 nodes
.swap(*newNodes
);
165 nodes
.markSorted(resultIsSorted
);
168 void LocationPath::appendStep(Step
* step
)
170 unsigned stepCount
= m_steps
.size();
171 if (stepCount
&& optimizeStepPair(m_steps
[stepCount
- 1], step
))
174 m_steps
.append(step
);
177 void LocationPath::insertFirstStep(Step
* step
)
179 if (m_steps
.size() && optimizeStepPair(step
, m_steps
[0])) {
184 m_steps
.insert(0, step
);
187 Path::Path(Expression
* filter
, LocationPath
* path
)
191 setIsContextNodeSensitive(filter
->isContextNodeSensitive());
192 setIsContextPositionSensitive(filter
->isContextPositionSensitive());
193 setIsContextSizeSensitive(filter
->isContextSizeSensitive());
202 visitor
->trace(m_filter
);
203 visitor
->trace(m_path
);
204 Expression::trace(visitor
);
207 Value
Path::evaluate(EvaluationContext
& context
) const
209 Value v
= m_filter
->evaluate(context
);
211 NodeSet
& nodes
= v
.modifiableNodeSet(context
);
212 m_path
->evaluate(context
, nodes
);