View | Details | Raw Unified | Return to bug 60991
Collapse All | Expand All

(-)LICENSE (+1 lines)
Lines 284-286 Link Here
284
* xpp3-1.1.4c.jar (Indiana University Extreme! Lab Software License 1.1.1)
284
* xpp3-1.1.4c.jar (Indiana University Extreme! Lab Software License 1.1.1)
285
* xstream-1.4.10.jar (BSD)
285
* xstream-1.4.10.jar (BSD)
286
* hamcrest-date-2.0.4.jar (BSD)
286
* hamcrest-date-2.0.4.jar (BSD)
287
* saxon9he-9.8.0.11.jar (Mozilla Public License version 2.0)
(-)bin/saveservice.properties (-1 / +3 lines)
Lines 364-370 Link Here
364
XPathAssertionGui=org.apache.jmeter.assertions.gui.XPathAssertionGui
364
XPathAssertionGui=org.apache.jmeter.assertions.gui.XPathAssertionGui
365
XPathExtractor=org.apache.jmeter.extractor.XPathExtractor
365
XPathExtractor=org.apache.jmeter.extractor.XPathExtractor
366
XPathExtractorGui=org.apache.jmeter.extractor.gui.XPathExtractorGui
366
XPathExtractorGui=org.apache.jmeter.extractor.gui.XPathExtractorGui
367
#
367
XPath2Extractor=org.apache.jmeter.extractor.XPath2Extractor
368
XPath2ExtractorGui=org.apache.jmeter.extractor.gui.XPath2ExtractorGui
369
368
# Properties - all start with lower case letter and end with Prop
370
# Properties - all start with lower case letter and end with Prop
369
#
371
#
370
boolProp=org.apache.jmeter.testelement.property.BooleanProperty
372
boolProp=org.apache.jmeter.testelement.property.BooleanProperty
(-)build.properties (+6 lines)
Lines 473-478 Link Here
473
activemq-all.loc             = ${maven2.repo}/org/apache/activemq/activemq-all/${activemq-all.version}
473
activemq-all.loc             = ${maven2.repo}/org/apache/activemq/activemq-all/${activemq-all.version}
474
activemq-all.md5             = bd24ae082be11dc969a6e5bc45515ab7
474
activemq-all.md5             = bd24ae082be11dc969a6e5bc45515ab7
475
475
476
# Used by XPath 2
477
saxon-HE.version              = 9.8.0-12
478
saxon-HE.jar                  = Saxon-HE-${saxon-HE.version}.jar
479
saxon-HE.loc                 = ${maven2.repo}/net/sf/saxon/Saxon-HE/${saxon-HE.version}
480
saxon-HE.md5                  = 80e040add296c6545b92d7cb1b648534
481
476
# Optional for use by FTP_TESTS.jmx
482
# Optional for use by FTP_TESTS.jmx
477
mina-core.version            = 2.0.16
483
mina-core.version            = 2.0.16
478
mina-core.jar                = mina-core-${mina-core.version}.jar
484
mina-core.jar                = mina-core-${mina-core.version}.jar
(-)build.xml (+3 lines)
Lines 446-451 Link Here
446
    <include name="${lib.dir}/${tika-core.jar}"/>
446
    <include name="${lib.dir}/${tika-core.jar}"/>
447
    <include name="${lib.dir}/${tika-parsers.jar}"/>
447
    <include name="${lib.dir}/${tika-parsers.jar}"/>
448
    <include name="${lib.dir}/${xalan.jar}"/>
448
    <include name="${lib.dir}/${xalan.jar}"/>
449
    <include name="${lib.dir}/${saxon-HE.jar}"/>
449
    <include name="${lib.dir}/${xerces.jar}"/>
450
    <include name="${lib.dir}/${xerces.jar}"/>
450
    <include name="${lib.dir}/${xml-apis.jar}"/>
451
    <include name="${lib.dir}/${xml-apis.jar}"/>
451
    <include name="${lib.dir}/${xmlgraphics-commons.jar}"/>
452
    <include name="${lib.dir}/${xmlgraphics-commons.jar}"/>
Lines 532-537 Link Here
532
    <pathelement location="${lib.dir}/${tika-core.jar}"/>
533
    <pathelement location="${lib.dir}/${tika-core.jar}"/>
533
    <pathelement location="${lib.dir}/${tika-parsers.jar}"/>
534
    <pathelement location="${lib.dir}/${tika-parsers.jar}"/>
534
    <pathelement location="${lib.dir}/${xalan.jar}"/>
535
    <pathelement location="${lib.dir}/${xalan.jar}"/>
536
    <pathelement location="${lib.dir}/${saxon-HE.jar}"/>
535
    <pathelement location="${lib.dir}/${xerces.jar}"/>
537
    <pathelement location="${lib.dir}/${xerces.jar}"/>
536
    <pathelement location="${lib.dir}/${xml-apis.jar}"/>
538
    <pathelement location="${lib.dir}/${xml-apis.jar}"/>
537
    <pathelement location="${lib.dir}/${xmlgraphics-commons.jar}"/>
539
    <pathelement location="${lib.dir}/${xmlgraphics-commons.jar}"/>
Lines 3400-3405 Link Here
3400
    <process_jarfile jarname="velocity"   dest.dir="${lib.doc}"/>
3402
    <process_jarfile jarname="velocity"   dest.dir="${lib.doc}"/>
3401
    <process_jarfile jarname="commons-lang" dest.dir="${lib.doc}"/>
3403
    <process_jarfile jarname="commons-lang" dest.dir="${lib.doc}"/>
3402
    <process_jarfile jarname="xalan"/>
3404
    <process_jarfile jarname="xalan"/>
3405
    <process_jarfile jarname="saxon-HE"/>
3403
    <process_jarfile jarname="xerces"/>
3406
    <process_jarfile jarname="xerces"/>
3404
    <process_jarfile jarname="xml-apis"/>
3407
    <process_jarfile jarname="xml-apis"/>
3405
    <process_jarfile jarname="xmlgraphics-commons"/>
3408
    <process_jarfile jarname="xmlgraphics-commons"/>
(-)eclipse.classpath (+1 lines)
Lines 97-102 Link Here
97
	<classpathentry kind="lib" path="lib/ph-commons-9.0.0.jar"/>
97
	<classpathentry kind="lib" path="lib/ph-commons-9.0.0.jar"/>
98
	<classpathentry kind="lib" path="lib/rhino-1.7.7.2.jar"/>
98
	<classpathentry kind="lib" path="lib/rhino-1.7.7.2.jar"/>
99
	<classpathentry kind="lib" path="lib/rsyntaxtextarea-2.6.1.jar"/>
99
	<classpathentry kind="lib" path="lib/rsyntaxtextarea-2.6.1.jar"/>
100
	<classpathentry kind="lib" path="lib/saxon9he-9.8.0.11.jar"/>
100
	<classpathentry kind="lib" path="lib/serializer-2.7.2.jar"/>
101
	<classpathentry kind="lib" path="lib/serializer-2.7.2.jar"/>
101
	<classpathentry kind="lib" path="lib/slf4j-api-1.7.25.jar"/>
102
	<classpathentry kind="lib" path="lib/slf4j-api-1.7.25.jar"/>
102
	<classpathentry kind="lib" path="lib/slf4j-ext-1.7.25.jar"/>
103
	<classpathentry kind="lib" path="lib/slf4j-ext-1.7.25.jar"/>
(-)lib/aareadme.txt (+4 lines)
Lines 249-254 Link Here
249
--------------------------
249
--------------------------
250
- DataSourceElement (JDBC)
250
- DataSourceElement (JDBC)
251
251
252
Saxon-HE-9.8.0-12 (net.sf.saxon)
253
--------------------------
254
- XPath2Extractor (XML)
255
252
velocity-1.7
256
velocity-1.7
253
--------------
257
--------------
254
http://velocity.apache.org/download.cgi
258
http://velocity.apache.org/download.cgi
(-)licenses/bin/saxon-HE-9.8.0-12.txt (+373 lines)
Line 0 Link Here
1
Mozilla Public License Version 2.0
2
==================================
3
4
1. Definitions
5
--------------
6
7
1.1. "Contributor"
8
    means each individual or legal entity that creates, contributes to
9
    the creation of, or owns Covered Software.
10
11
1.2. "Contributor Version"
12
    means the combination of the Contributions of others (if any) used
13
    by a Contributor and that particular Contributor's Contribution.
14
15
1.3. "Contribution"
16
    means Covered Software of a particular Contributor.
17
18
1.4. "Covered Software"
19
    means Source Code Form to which the initial Contributor has attached
20
    the notice in Exhibit A, the Executable Form of such Source Code
21
    Form, and Modifications of such Source Code Form, in each case
22
    including portions thereof.
23
24
1.5. "Incompatible With Secondary Licenses"
25
    means
26
27
    (a) that the initial Contributor has attached the notice described
28
        in Exhibit B to the Covered Software; or
29
30
    (b) that the Covered Software was made available under the terms of
31
        version 1.1 or earlier of the License, but not also under the
32
        terms of a Secondary License.
33
34
1.6. "Executable Form"
35
    means any form of the work other than Source Code Form.
36
37
1.7. "Larger Work"
38
    means a work that combines Covered Software with other material, in 
39
    a separate file or files, that is not Covered Software.
40
41
1.8. "License"
42
    means this document.
43
44
1.9. "Licensable"
45
    means having the right to grant, to the maximum extent possible,
46
    whether at the time of the initial grant or subsequently, any and
47
    all of the rights conveyed by this License.
48
49
1.10. "Modifications"
50
    means any of the following:
51
52
    (a) any file in Source Code Form that results from an addition to,
53
        deletion from, or modification of the contents of Covered
54
        Software; or
55
56
    (b) any new file in Source Code Form that contains any Covered
57
        Software.
58
59
1.11. "Patent Claims" of a Contributor
60
    means any patent claim(s), including without limitation, method,
61
    process, and apparatus claims, in any patent Licensable by such
62
    Contributor that would be infringed, but for the grant of the
63
    License, by the making, using, selling, offering for sale, having
64
    made, import, or transfer of either its Contributions or its
65
    Contributor Version.
66
67
1.12. "Secondary License"
68
    means either the GNU General Public License, Version 2.0, the GNU
69
    Lesser General Public License, Version 2.1, the GNU Affero General
70
    Public License, Version 3.0, or any later versions of those
71
    licenses.
72
73
1.13. "Source Code Form"
74
    means the form of the work preferred for making modifications.
75
76
1.14. "You" (or "Your")
77
    means an individual or a legal entity exercising rights under this
78
    License. For legal entities, "You" includes any entity that
79
    controls, is controlled by, or is under common control with You. For
80
    purposes of this definition, "control" means (a) the power, direct
81
    or indirect, to cause the direction or management of such entity,
82
    whether by contract or otherwise, or (b) ownership of more than
83
    fifty percent (50%) of the outstanding shares or beneficial
84
    ownership of such entity.
85
86
2. License Grants and Conditions
87
--------------------------------
88
89
2.1. Grants
90
91
Each Contributor hereby grants You a world-wide, royalty-free,
92
non-exclusive license:
93
94
(a) under intellectual property rights (other than patent or trademark)
95
    Licensable by such Contributor to use, reproduce, make available,
96
    modify, display, perform, distribute, and otherwise exploit its
97
    Contributions, either on an unmodified basis, with Modifications, or
98
    as part of a Larger Work; and
99
100
(b) under Patent Claims of such Contributor to make, use, sell, offer
101
    for sale, have made, import, and otherwise transfer either its
102
    Contributions or its Contributor Version.
103
104
2.2. Effective Date
105
106
The licenses granted in Section 2.1 with respect to any Contribution
107
become effective for each Contribution on the date the Contributor first
108
distributes such Contribution.
109
110
2.3. Limitations on Grant Scope
111
112
The licenses granted in this Section 2 are the only rights granted under
113
this License. No additional rights or licenses will be implied from the
114
distribution or licensing of Covered Software under this License.
115
Notwithstanding Section 2.1(b) above, no patent license is granted by a
116
Contributor:
117
118
(a) for any code that a Contributor has removed from Covered Software;
119
    or
120
121
(b) for infringements caused by: (i) Your and any other third party's
122
    modifications of Covered Software, or (ii) the combination of its
123
    Contributions with other software (except as part of its Contributor
124
    Version); or
125
126
(c) under Patent Claims infringed by Covered Software in the absence of
127
    its Contributions.
128
129
This License does not grant any rights in the trademarks, service marks,
130
or logos of any Contributor (except as may be necessary to comply with
131
the notice requirements in Section 3.4).
132
133
2.4. Subsequent Licenses
134
135
No Contributor makes additional grants as a result of Your choice to
136
distribute the Covered Software under a subsequent version of this
137
License (see Section 10.2) or under the terms of a Secondary License (if
138
permitted under the terms of Section 3.3).
139
140
2.5. Representation
141
142
Each Contributor represents that the Contributor believes its
143
Contributions are its original creation(s) or it has sufficient rights
144
to grant the rights to its Contributions conveyed by this License.
145
146
2.6. Fair Use
147
148
This License is not intended to limit any rights You have under
149
applicable copyright doctrines of fair use, fair dealing, or other
150
equivalents.
151
152
2.7. Conditions
153
154
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155
in Section 2.1.
156
157
3. Responsibilities
158
-------------------
159
160
3.1. Distribution of Source Form
161
162
All distribution of Covered Software in Source Code Form, including any
163
Modifications that You create or to which You contribute, must be under
164
the terms of this License. You must inform recipients that the Source
165
Code Form of the Covered Software is governed by the terms of this
166
License, and how they can obtain a copy of this License. You may not
167
attempt to alter or restrict the recipients' rights in the Source Code
168
Form.
169
170
3.2. Distribution of Executable Form
171
172
If You distribute Covered Software in Executable Form then:
173
174
(a) such Covered Software must also be made available in Source Code
175
    Form, as described in Section 3.1, and You must inform recipients of
176
    the Executable Form how they can obtain a copy of such Source Code
177
    Form by reasonable means in a timely manner, at a charge no more
178
    than the cost of distribution to the recipient; and
179
180
(b) You may distribute such Executable Form under the terms of this
181
    License, or sublicense it under different terms, provided that the
182
    license for the Executable Form does not attempt to limit or alter
183
    the recipients' rights in the Source Code Form under this License.
184
185
3.3. Distribution of a Larger Work
186
187
You may create and distribute a Larger Work under terms of Your choice,
188
provided that You also comply with the requirements of this License for
189
the Covered Software. If the Larger Work is a combination of Covered
190
Software with a work governed by one or more Secondary Licenses, and the
191
Covered Software is not Incompatible With Secondary Licenses, this
192
License permits You to additionally distribute such Covered Software
193
under the terms of such Secondary License(s), so that the recipient of
194
the Larger Work may, at their option, further distribute the Covered
195
Software under the terms of either this License or such Secondary
196
License(s).
197
198
3.4. Notices
199
200
You may not remove or alter the substance of any license notices
201
(including copyright notices, patent notices, disclaimers of warranty,
202
or limitations of liability) contained within the Source Code Form of
203
the Covered Software, except that You may alter any license notices to
204
the extent required to remedy known factual inaccuracies.
205
206
3.5. Application of Additional Terms
207
208
You may choose to offer, and to charge a fee for, warranty, support,
209
indemnity or liability obligations to one or more recipients of Covered
210
Software. However, You may do so only on Your own behalf, and not on
211
behalf of any Contributor. You must make it absolutely clear that any
212
such warranty, support, indemnity, or liability obligation is offered by
213
You alone, and You hereby agree to indemnify every Contributor for any
214
liability incurred by such Contributor as a result of warranty, support,
215
indemnity or liability terms You offer. You may include additional
216
disclaimers of warranty and limitations of liability specific to any
217
jurisdiction.
218
219
4. Inability to Comply Due to Statute or Regulation
220
---------------------------------------------------
221
222
If it is impossible for You to comply with any of the terms of this
223
License with respect to some or all of the Covered Software due to
224
statute, judicial order, or regulation then You must: (a) comply with
225
the terms of this License to the maximum extent possible; and (b)
226
describe the limitations and the code they affect. Such description must
227
be placed in a text file included with all distributions of the Covered
228
Software under this License. Except to the extent prohibited by statute
229
or regulation, such description must be sufficiently detailed for a
230
recipient of ordinary skill to be able to understand it.
231
232
5. Termination
233
--------------
234
235
5.1. The rights granted under this License will terminate automatically
236
if You fail to comply with any of its terms. However, if You become
237
compliant, then the rights granted under this License from a particular
238
Contributor are reinstated (a) provisionally, unless and until such
239
Contributor explicitly and finally terminates Your grants, and (b) on an
240
ongoing basis, if such Contributor fails to notify You of the
241
non-compliance by some reasonable means prior to 60 days after You have
242
come back into compliance. Moreover, Your grants from a particular
243
Contributor are reinstated on an ongoing basis if such Contributor
244
notifies You of the non-compliance by some reasonable means, this is the
245
first time You have received notice of non-compliance with this License
246
from such Contributor, and You become compliant prior to 30 days after
247
Your receipt of the notice.
248
249
5.2. If You initiate litigation against any entity by asserting a patent
250
infringement claim (excluding declaratory judgment actions,
251
counter-claims, and cross-claims) alleging that a Contributor Version
252
directly or indirectly infringes any patent, then the rights granted to
253
You by any and all Contributors for the Covered Software under Section
254
2.1 of this License shall terminate.
255
256
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257
end user license agreements (excluding distributors and resellers) which
258
have been validly granted by You or Your distributors under this License
259
prior to termination shall survive termination.
260
261
************************************************************************
262
*                                                                      *
263
*  6. Disclaimer of Warranty                                           *
264
*  -------------------------                                           *
265
*                                                                      *
266
*  Covered Software is provided under this License on an "as is"       *
267
*  basis, without warranty of any kind, either expressed, implied, or  *
268
*  statutory, including, without limitation, warranties that the       *
269
*  Covered Software is free of defects, merchantable, fit for a        *
270
*  particular purpose or non-infringing. The entire risk as to the     *
271
*  quality and performance of the Covered Software is with You.        *
272
*  Should any Covered Software prove defective in any respect, You     *
273
*  (not any Contributor) assume the cost of any necessary servicing,   *
274
*  repair, or correction. This disclaimer of warranty constitutes an   *
275
*  essential part of this License. No use of any Covered Software is   *
276
*  authorized under this License except under this disclaimer.         *
277
*                                                                      *
278
************************************************************************
279
280
************************************************************************
281
*                                                                      *
282
*  7. Limitation of Liability                                          *
283
*  --------------------------                                          *
284
*                                                                      *
285
*  Under no circumstances and under no legal theory, whether tort      *
286
*  (including negligence), contract, or otherwise, shall any           *
287
*  Contributor, or anyone who distributes Covered Software as          *
288
*  permitted above, be liable to You for any direct, indirect,         *
289
*  special, incidental, or consequential damages of any character      *
290
*  including, without limitation, damages for lost profits, loss of    *
291
*  goodwill, work stoppage, computer failure or malfunction, or any    *
292
*  and all other commercial damages or losses, even if such party      *
293
*  shall have been informed of the possibility of such damages. This   *
294
*  limitation of liability shall not apply to liability for death or   *
295
*  personal injury resulting from such party's negligence to the       *
296
*  extent applicable law prohibits such limitation. Some               *
297
*  jurisdictions do not allow the exclusion or limitation of           *
298
*  incidental or consequential damages, so this exclusion and          *
299
*  limitation may not apply to You.                                    *
300
*                                                                      *
301
************************************************************************
302
303
8. Litigation
304
-------------
305
306
Any litigation relating to this License may be brought only in the
307
courts of a jurisdiction where the defendant maintains its principal
308
place of business and such litigation shall be governed by laws of that
309
jurisdiction, without reference to its conflict-of-law provisions.
310
Nothing in this Section shall prevent a party's ability to bring
311
cross-claims or counter-claims.
312
313
9. Miscellaneous
314
----------------
315
316
This License represents the complete agreement concerning the subject
317
matter hereof. If any provision of this License is held to be
318
unenforceable, such provision shall be reformed only to the extent
319
necessary to make it enforceable. Any law or regulation which provides
320
that the language of a contract shall be construed against the drafter
321
shall not be used to construe this License against a Contributor.
322
323
10. Versions of the License
324
---------------------------
325
326
10.1. New Versions
327
328
Mozilla Foundation is the license steward. Except as provided in Section
329
10.3, no one other than the license steward has the right to modify or
330
publish new versions of this License. Each version will be given a
331
distinguishing version number.
332
333
10.2. Effect of New Versions
334
335
You may distribute the Covered Software under the terms of the version
336
of the License under which You originally received the Covered Software,
337
or under the terms of any subsequent version published by the license
338
steward.
339
340
10.3. Modified Versions
341
342
If you create software not governed by this License, and you want to
343
create a new license for such software, you may create and use a
344
modified version of this License if you rename the license and remove
345
any references to the name of the license steward (except to note that
346
such modified license differs from this License).
347
348
10.4. Distributing Source Code Form that is Incompatible With Secondary
349
Licenses
350
351
If You choose to distribute Source Code Form that is Incompatible With
352
Secondary Licenses under the terms of this version of the License, the
353
notice described in Exhibit B of this License must be attached.
354
355
Exhibit A - Source Code Form License Notice
356
-------------------------------------------
357
358
  This Source Code Form is subject to the terms of the Mozilla Public
359
  License, v. 2.0. If a copy of the MPL was not distributed with this
360
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
361
362
If it is not possible or desirable to put the notice in a particular
363
file, then You may include the notice in a location (such as a LICENSE
364
file in a relevant directory) where a recipient would be likely to look
365
for such a notice.
366
367
You may add additional accurate notices of copyright ownership.
368
369
Exhibit B - "Incompatible With Secondary Licenses" Notice
370
---------------------------------------------------------
371
372
  This Source Code Form is "Incompatible With Secondary Licenses", as
373
  defined by the Mozilla Public License, v. 2.0.
(-)res/maven/ApacheJMeter_parent.pom (+6 lines)
Lines 99-104 Link Here
99
      <ph-css.version>6.0.0</ph-css.version>
99
      <ph-css.version>6.0.0</ph-css.version>
100
      <ph-commons.version>9.0.0</ph-commons.version>
100
      <ph-commons.version>9.0.0</ph-commons.version>
101
      <rsyntaxtextarea.version>2.6.1</rsyntaxtextarea.version>
101
      <rsyntaxtextarea.version>2.6.1</rsyntaxtextarea.version>
102
      <saxon-HE.version>9.8.0-12</saxon-HE.version>
102
      <slf4j-api.version>1.7.25</slf4j-api.version>
103
      <slf4j-api.version>1.7.25</slf4j-api.version>
103
      <slf4j-ext.version>1.7.25</slf4j-ext.version>
104
      <slf4j-ext.version>1.7.25</slf4j-ext.version>
104
      <log4j-api.version>2.10.0</log4j-api.version>
105
      <log4j-api.version>2.10.0</log4j-api.version>
Lines 333-338 Link Here
333
        <version>${serializer.version}</version>
334
        <version>${serializer.version}</version>
334
      </dependency>
335
      </dependency>
335
      <dependency>
336
      <dependency>
337
        <groupId>net.sf.saxon</groupId>
338
        <artifactId>Saxon-HE</artifactId>
339
        <version>${saxon-HE.version}</version>
340
      </dependency>
341
      <dependency>
336
        <groupId>xerces</groupId>
342
        <groupId>xerces</groupId>
337
        <artifactId>xercesImpl</artifactId>
343
        <artifactId>xercesImpl</artifactId>
338
        <version>${xerces.version}</version>
344
        <version>${xerces.version}</version>
(-)src/components/org/apache/jmeter/extractor/XPath2Extractor.java (+359 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
package org.apache.jmeter.extractor;
19
20
import java.io.Serializable;
21
import java.util.ArrayList;
22
import java.util.List;
23
24
import javax.xml.stream.FactoryConfigurationError;
25
import javax.xml.stream.XMLStreamException;
26
27
import org.apache.jmeter.assertions.AssertionResult;
28
import org.apache.jmeter.processor.PostProcessor;
29
import org.apache.jmeter.samplers.SampleResult;
30
import org.apache.jmeter.testelement.AbstractScopedTestElement;
31
import org.apache.jmeter.testelement.property.BooleanProperty;
32
import org.apache.jmeter.testelement.property.IntegerProperty;
33
import org.apache.jmeter.threads.JMeterContext;
34
import org.apache.jmeter.threads.JMeterVariables;
35
import org.apache.jmeter.util.XPathUtil;
36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38
39
import net.sf.saxon.s9api.SaxonApiException;
40
41
/**
42
 * Extracts text from (X)HTML response using XPath query language
43
 * Example XPath queries:
44
 * <dl>
45
 * <dt>/html/head/title</dt>
46
 *     <dd>extracts Title from HTML response</dd>
47
 * <dt>//form[@name='countryForm']//select[@name='country']/option[text()='Czech Republic'])/@value
48
 *     <dd>extracts value attribute of option element that match text 'Czech Republic'
49
 *                 inside of select element with name attribute  'country' inside of
50
 *                 form with name attribute 'countryForm'</dd>
51
 * <dt>//head</dt>
52
 *     <dd>extracts the XML fragment for head node.</dd>
53
 * <dt>//head/text()</dt>
54
 *     <dd>extracts the text content for head node.</dd>
55
 * </dl>
56
  see org.apache.jmeter.extractor.TestXPathExtractor for unit tests
57
 */
58
public class XPath2Extractor extends AbstractScopedTestElement implements
59
PostProcessor, Serializable {
60
    private static final Logger log = LoggerFactory.getLogger(XPathExtractor.class);
61
62
    private static final long serialVersionUID = 242L;
63
64
    private static final int DEFAULT_VALUE = -1;
65
    public static final String DEFAULT_VALUE_AS_STRING = Integer.toString(DEFAULT_VALUE);
66
67
    private static final String REF_MATCH_NR    = "matchNr"; // $NON-NLS-1$
68
69
    //+ JMX file attributes
70
    private static final String XPATH_QUERY     = "XPathExtractor2.xpathQuery"; // $NON-NLS-1$
71
    private static final String REFNAME         = "XPathExtractor2.refname"; // $NON-NLS-1$
72
    private static final String DEFAULT         = "XPathExtractor2.default"; // $NON-NLS-1$
73
    private static final String TOLERANT        = "XPathExtractor2.tolerant"; // $NON-NLS-1$
74
    private static final String QUIET           = "XPathExtractor2.quiet"; // $NON-NLS-1$
75
    private static final String REPORT_ERRORS   = "XPathExtractor2.report_errors"; // $NON-NLS-1$
76
    private static final String SHOW_WARNINGS   = "XPathExtractor2.show_warnings"; // $NON-NLS-1$
77
    private static final String DOWNLOAD_DTDS   = "XPathExtractor2.download_dtds"; // $NON-NLS-1$
78
    private static final String WHITESPACE      = "XPathExtractor2.whitespace"; // $NON-NLS-1$
79
    private static final String VALIDATE        = "XPathExtractor2.validate"; // $NON-NLS-1$
80
    private static final String FRAGMENT        = "XPathExtractor2.fragment"; // $NON-NLS-1$
81
    private static final String NAMESPACES      = "XPathExtractor2.namespaces"; // $NON-NLS-1$
82
    private static final String MATCH_NUMBER    = "XPathExtractor2.matchNumber"; // $NON-NLS-1$
83
    //- JMX file attributes
84
85
    private String concat(String s1,String s2){
86
        return new StringBuilder(s1).append("_").append(s2).toString(); // $NON-NLS-1$
87
    }
88
89
    private String concat(String s1, int i){
90
        return new StringBuilder(s1).append("_").append(i).toString(); // $NON-NLS-1$
91
    }
92
93
94
    /**
95
     * Do the job - extract value from (X)HTML response using XPath Query.
96
     * Return value as variable defined by REFNAME. Returns DEFAULT value
97
     * if not found.
98
     */
99
    @Override
100
    public void process() {
101
        JMeterContext context = getThreadContext();
102
        final SampleResult previousResult = context.getPreviousResult();
103
        if (previousResult == null){
104
            return;
105
        }
106
        JMeterVariables vars = context.getVariables();
107
        String refName = getRefName();
108
        vars.put(refName, getDefaultValue());
109
        final String matchNR = concat(refName,REF_MATCH_NR);
110
        int prevCount=0; // number of previous matches
111
        try {
112
            prevCount=Integer.parseInt(vars.get(matchNR));
113
        } catch (NumberFormatException e) {
114
            // ignored
115
        }
116
117
        vars.put(matchNR, "0"); // In case parse fails // $NON-NLS-1$
118
        vars.remove(concat(refName,"1")); // In case parse fails // $NON-NLS-1$
119
120
        int matchNumber = getMatchNumber();
121
        List<String> matches = new ArrayList<>();
122
        try{
123
            if (isScopeVariable()){
124
                String inputString=vars.get(getVariableName());
125
                if(inputString != null) {
126
                    if(inputString.length()>0) {
127
                        getValuesForXPath(getXPathQuery(), matches, matchNumber,previousResult.getResponseDataAsString());
128
                    }
129
                } else {
130
                    if (log.isWarnEnabled()) {
131
                        log.warn("No variable '{}' found to process by XPathExtractor '{}', skipping processing",
132
                                getVariableName(), getName());
133
                    }
134
                }
135
            } else {
136
                List<SampleResult> samples = getSampleList(previousResult);
137
                int size = samples.size();
138
                for(int i = 0;i<size;i++) {
139
                    getValuesForXPath(getXPathQuery(), matches, matchNumber,previousResult.getResponseDataAsString());
140
                }
141
            }
142
            final int matchCount = matches.size();
143
            vars.put(matchNR, String.valueOf(matchCount));
144
            if (matchCount > 0){
145
                String value = matches.get(0);
146
                if (value != null) {
147
                    vars.put(refName, value);
148
                }
149
                for(int i=0; i < matchCount; i++){
150
                    value = matches.get(i);
151
                    if (value != null) {
152
                        vars.put(concat(refName,i+1),matches.get(i));
153
                    }
154
                }
155
            }
156
            vars.remove(concat(refName,matchCount+1)); // Just in case
157
            // Clear any other remaining variables
158
            for(int i=matchCount+2; i <= prevCount; i++) {
159
                vars.remove(concat(refName,i));
160
            }
161
        }catch (SaxonApiException e) {// Saxon exception
162
            if (log.isWarnEnabled()) {
163
                log.warn("SaxonApiException while processing ({}). {}", getXPathQuery(), e.getLocalizedMessage());
164
            }
165
            addAssertionFailure(previousResult, e, false);
166
        } catch (XMLStreamException e) {
167
            log.error("XMLStreamException on {}", e);
168
            log.warn("XMLStreamException while processing {}", e.getLocalizedMessage());
169
        } catch (FactoryConfigurationError e) {
170
            log.error("FactoryConfigurationError on {}", e);
171
            log.warn("FactoryConfigurationError while processing {}", e.getLocalizedMessage());
172
173
        }
174
    }
175
176
    private void addAssertionFailure(final SampleResult previousResult,
177
            final Throwable thrown, final boolean setFailed) {
178
        AssertionResult ass = new AssertionResult(getName()); // $NON-NLS-1$
179
        ass.setFailure(true);
180
        ass.setFailureMessage(thrown.getLocalizedMessage()+"\nSee log file for further details.");
181
        previousResult.addAssertionResult(ass);
182
        if (setFailed){
183
            previousResult.setSuccessful(false);
184
        }
185
    }
186
187
    /*============= object properties ================*/
188
    public void setXPathQuery(String val){
189
        setProperty(XPATH_QUERY,val);
190
    }
191
192
    public String getXPathQuery(){
193
        return getPropertyAsString(XPATH_QUERY);
194
    }
195
196
    public void setRefName(String refName) {
197
        setProperty(REFNAME, refName);
198
    }
199
200
    public String getRefName() {
201
        return getPropertyAsString(REFNAME);
202
    }
203
204
205
    public void setDefaultValue(String val) {
206
        setProperty(DEFAULT, val);
207
    }
208
209
    public String getDefaultValue() {
210
        return getPropertyAsString(DEFAULT);
211
    }
212
213
    public void setTolerant(boolean val) {
214
        setProperty(new BooleanProperty(TOLERANT, val));
215
    }
216
217
    public boolean isTolerant() {
218
        return getPropertyAsBoolean(TOLERANT);
219
    }
220
221
    public void setNameSpace(boolean val) {
222
        setProperty(new BooleanProperty(NAMESPACES, val));
223
    }
224
225
    public boolean useNameSpace() {
226
        return getPropertyAsBoolean(NAMESPACES);
227
    }
228
229
    public void setReportErrors(boolean val) {
230
        setProperty(REPORT_ERRORS, val, false);
231
    }
232
233
    public boolean reportErrors() {
234
        return getPropertyAsBoolean(REPORT_ERRORS, false);
235
    }
236
237
    public void setShowWarnings(boolean val) {
238
        setProperty(SHOW_WARNINGS, val, false);
239
    }
240
241
    public boolean showWarnings() {
242
        return getPropertyAsBoolean(SHOW_WARNINGS, false);
243
    }
244
245
    public void setQuiet(boolean val) {
246
        setProperty(QUIET, val, true);
247
    }
248
249
    public boolean isQuiet() {
250
        return getPropertyAsBoolean(QUIET, true);
251
    }
252
253
    /**
254
     * Should we return fragment as text, rather than text of fragment?
255
     * @return true if we should return fragment rather than text
256
     */
257
    public boolean getFragment() {
258
        return getPropertyAsBoolean(FRAGMENT, false);
259
    }
260
261
    /**
262
     * Should we return fragment as text, rather than text of fragment?
263
     * @param selected true to return fragment.
264
     */
265
    public void setFragment(boolean selected) {
266
        setProperty(FRAGMENT, selected, false);
267
    }
268
269
    /*================= internal business =================*/
270
271
    /**
272
     * Extract value from String responseData by XPath query.
273
     * @param query the query to execute
274
     * @param matchStrings list of matched strings (may include nulls)
275
     * @param matchNumber int Match Number
276
     * @param responseData String that contains the entire Document
277
     * @throws SaxonApiException
278
     * @throws XMLStreamException 
279
     * @throws FactoryConfigurationError 
280
     */
281
    private void getValuesForXPath(String query, List<String> matchStrings, int matchNumber, String responseData)
282
            throws SaxonApiException, XMLStreamException, FactoryConfigurationError {
283
        XPathUtil.putValuesForXPathInListUsingSaxon(responseData, query, matchStrings, getFragment(), matchNumber, getNamespaces());
284
    }
285
286
287
288
    public void setWhitespace(boolean selected) {
289
        setProperty(WHITESPACE, selected, false);
290
    }
291
292
    public boolean isWhitespace() {
293
        return getPropertyAsBoolean(WHITESPACE, false);
294
    }
295
296
    public void setValidating(boolean selected) {
297
        setProperty(VALIDATE, selected);
298
    }
299
300
    public boolean isValidating() {
301
        return getPropertyAsBoolean(VALIDATE, false);
302
    }
303
304
    public void setDownloadDTDs(boolean selected) {
305
        setProperty(DOWNLOAD_DTDS, selected, false);
306
    }
307
308
    public boolean isDownloadDTDs() {
309
        return getPropertyAsBoolean(DOWNLOAD_DTDS, false);
310
    }
311
312
    /**
313
     * Set which Match to use. This can be any positive number, indicating the
314
     * exact match to use, or <code>0</code>, which is interpreted as meaning random.
315
     *
316
     * @param matchNumber The number of the match to be used
317
     */
318
    public void setMatchNumber(int matchNumber) {
319
        setProperty(new IntegerProperty(MATCH_NUMBER, matchNumber));
320
    }
321
322
    /**
323
     * Set which Match to use. This can be any positive number, indicating the
324
     * exact match to use, or <code>0</code>, which is interpreted as meaning random.
325
     *
326
     * @param matchNumber The number of the match to be used
327
     */
328
    public void setMatchNumber(String matchNumber) {
329
        setProperty(MATCH_NUMBER, matchNumber);
330
    }
331
332
    /**
333
     * Return which Match to use. This can be any positive number, indicating the
334
     * exact match to use, or <code>0</code>, which is interpreted as meaning random.
335
     *
336
     * @return matchNumber The number of the match to be used
337
     */
338
    public int getMatchNumber() {
339
        return getPropertyAsInt(MATCH_NUMBER, DEFAULT_VALUE);
340
    }
341
342
    /**
343
     * Return which Match to use. This can be any positive number, indicating the
344
     * exact match to use, or <code>0</code>, which is interpreted as meaning random.
345
     *
346
     * @return matchNumber The number of the match to be used
347
     */
348
    public String getMatchNumberAsString() {
349
        return getPropertyAsString(MATCH_NUMBER, DEFAULT_VALUE_AS_STRING);
350
    }
351
352
    public void setNamespaces(String namespaces) {
353
        setProperty(NAMESPACES, namespaces);
354
    }
355
356
    public String getNamespaces() {
357
        return getPropertyAsString(NAMESPACES);
358
    }
359
}
(-)src/components/org/apache/jmeter/extractor/gui/XPath2ExtractorGui.java (+183 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
package org.apache.jmeter.extractor.gui;
19
20
import java.awt.BorderLayout;
21
import java.awt.GridBagConstraints;
22
import java.awt.GridBagLayout;
23
import java.util.List;
24
25
import javax.swing.Box;
26
import javax.swing.JCheckBox;
27
import javax.swing.JComponent;
28
import javax.swing.JLabel;
29
import javax.swing.JPanel;
30
31
import org.apache.jmeter.extractor.XPath2Extractor;
32
import org.apache.jmeter.gui.util.JSyntaxTextArea;
33
import org.apache.jmeter.gui.util.JTextScrollPane;
34
import org.apache.jmeter.processor.gui.AbstractPostProcessorGui;
35
import org.apache.jmeter.testelement.TestElement;
36
import org.apache.jmeter.util.JMeterUtils;
37
import org.apache.jorphan.gui.JLabeledTextField;
38
39
/**
40
 * GUI for XPath2Extractor class.
41
 * @since 4.1
42
 */
43
public class XPath2ExtractorGui extends AbstractPostProcessorGui{ // NOSONAR Ignore parents warning
44
45
    private static final long serialVersionUID = 1L;
46
47
    private final JLabeledTextField defaultField = new JLabeledTextField(
48
            JMeterUtils.getResString("default_value_field"));//$NON-NLS-1$
49
50
    private final JLabeledTextField xpathQueryField = new JLabeledTextField(
51
            JMeterUtils.getResString("xpath_extractor_query"));//$NON-NLS-1$
52
53
    private final JLabeledTextField matchNumberField = new JLabeledTextField(
54
            JMeterUtils.getResString("match_num_field"));//$NON-NLS-1$
55
56
    private final JLabeledTextField refNameField = new JLabeledTextField(JMeterUtils.getResString("ref_name_field"));//$NON-NLS-1$
57
58
    // Should we return fragment as text, rather than text of fragment?
59
    private JCheckBox getFragment;
60
    
61
    private JSyntaxTextArea namespacesTA;
62
    
63
    @Override
64
    public String getLabelResource() {
65
        return "xpath2_extractor_title"; //$NON-NLS-1$
66
    }
67
68
    public XPath2ExtractorGui() {
69
        super();
70
        init();
71
    }
72
73
    @Override
74
    public void configure(TestElement el) {
75
        super.configure(el);
76
        XPath2Extractor xpe = (XPath2Extractor) el;
77
        showScopeSettings(xpe, true);
78
        xpathQueryField.setText(xpe.getXPathQuery());
79
        defaultField.setText(xpe.getDefaultValue());
80
        refNameField.setText(xpe.getRefName());
81
        matchNumberField.setText(xpe.getMatchNumberAsString());
82
        namespacesTA.setText(xpe.getNamespaces());
83
        getFragment.setSelected(xpe.getFragment());
84
    }
85
86
    @Override
87
    public TestElement createTestElement() {
88
        XPath2Extractor extractor = new XPath2Extractor();
89
        modifyTestElement(extractor);
90
        return extractor;
91
    }
92
93
    @Override
94
    public void modifyTestElement(TestElement extractor) {
95
        super.configureTestElement(extractor);
96
        if (extractor instanceof XPath2Extractor) {
97
            XPath2Extractor xpath = (XPath2Extractor) extractor;
98
            saveScopeSettings(xpath);
99
            xpath.setDefaultValue(defaultField.getText());
100
            xpath.setRefName(refNameField.getText());
101
            xpath.setMatchNumber(matchNumberField.getText());
102
            xpath.setXPathQuery(xpathQueryField.getText());
103
            xpath.setFragment(getFragment.isSelected());
104
            xpath.setNamespaces(namespacesTA.getText());
105
        }
106
    }
107
108
    /**
109
     * Implements JMeterGUIComponent.clearGui
110
     */
111
    @Override
112
    public void clearGui() {
113
        super.clearGui();
114
        xpathQueryField.setText(""); // $NON-NLS-1$
115
        defaultField.setText(""); // $NON-NLS-1$
116
        refNameField.setText(""); // $NON-NLS-1$
117
        matchNumberField.setText(XPath2Extractor.DEFAULT_VALUE_AS_STRING); // $NON-NLS-1$
118
        namespacesTA.setText("");
119
    }
120
121
    private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
122
        setLayout(new BorderLayout());
123
        setBorder(makeBorder());
124
        Box box = Box.createVerticalBox();
125
        box.add(makeTitlePanel());
126
        box.add(createScopePanel(true, true, true));
127
        box.add(makeParameterPanel());
128
        add(box, BorderLayout.NORTH);
129
    }
130
    
131
    private JPanel makeParameterPanel() {
132
        JPanel panel = new JPanel(new GridBagLayout());
133
        GridBagConstraints gbc = new GridBagConstraints();
134
        initConstraints(gbc);
135
        addField(panel, refNameField, gbc);
136
        resetContraints(gbc);
137
        addField(panel, xpathQueryField, gbc);
138
        resetContraints(gbc);
139
        addField(panel, matchNumberField, gbc);
140
        resetContraints(gbc);
141
        addField(panel, defaultField, gbc);
142
        resetContraints(gbc);
143
        panel.add(new JLabel(JMeterUtils.getResString("xpath_extractor_user_namespaces")), gbc.clone());
144
        gbc.gridx++;
145
        gbc.weightx = 1;
146
        gbc.fill = GridBagConstraints.HORIZONTAL;
147
        namespacesTA = JSyntaxTextArea.getInstance(5, 80);
148
        panel.add(JTextScrollPane.getInstance(namespacesTA, true), gbc.clone());
149
150
        resetContraints(gbc);
151
        gbc.gridwidth = 2;
152
        getFragment = new JCheckBox(JMeterUtils.getResString("xpath_extractor_fragment"));//$NON-NLS-1$
153
        panel.add(getFragment, gbc.clone());
154
        return panel;
155
    }
156
157
    private void addField(JPanel panel, JLabeledTextField field, GridBagConstraints gbc) {
158
        List<JComponent> item = field.getComponentList();
159
        panel.add(item.get(0), gbc.clone());
160
        gbc.gridx++;
161
        gbc.weightx = 1;
162
        gbc.fill = GridBagConstraints.HORIZONTAL;
163
        panel.add(item.get(1), gbc.clone());
164
    }
165
166
    private void resetContraints(GridBagConstraints gbc) {
167
        gbc.gridx = 0;
168
        gbc.gridy++;
169
        gbc.weightx = 0;
170
        gbc.fill = GridBagConstraints.NONE;
171
    }
172
173
    private void initConstraints(GridBagConstraints gbc) {
174
        gbc.anchor = GridBagConstraints.NORTHWEST;
175
        gbc.fill = GridBagConstraints.NONE;
176
        gbc.gridheight = 1;
177
        gbc.gridwidth = 1;
178
        gbc.gridx = 0;
179
        gbc.gridy = 0;
180
        gbc.weightx = 0;
181
        gbc.weighty = 0;
182
    }
183
}
(-)src/components/org/apache/jmeter/visualizers/RenderAsXPath2.java (+293 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements. See the NOTICE file distributed with this
4
 * work for additional information regarding copyright ownership. The ASF
5
 * licenses this file to You under the Apache License, Version 2.0 (the
6
 * "License"); you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 * 
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * 
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
package org.apache.jmeter.visualizers;
20
21
import java.awt.BorderLayout;
22
import java.awt.Color;
23
import java.awt.Dimension;
24
import java.awt.event.ActionEvent;
25
import java.awt.event.ActionListener;
26
import java.util.ArrayList;
27
import java.util.List;
28
29
import javax.swing.Box;
30
import javax.swing.JButton;
31
import javax.swing.JCheckBox;
32
import javax.swing.JPanel;
33
import javax.swing.JScrollPane;
34
import javax.swing.JSplitPane;
35
import javax.swing.JTabbedPane;
36
import javax.swing.JTextArea;
37
import javax.swing.border.Border;
38
import javax.swing.border.EmptyBorder;
39
40
import org.apache.commons.lang3.exception.ExceptionUtils;
41
import org.apache.jmeter.extractor.XPath2Extractor;
42
import org.apache.jmeter.gui.util.JSyntaxTextArea;
43
import org.apache.jmeter.gui.util.JTextScrollPane;
44
import org.apache.jmeter.samplers.SampleResult;
45
import org.apache.jmeter.util.JMeterUtils;
46
import org.apache.jmeter.util.XPathUtil;
47
import org.apache.jorphan.gui.GuiUtils;
48
import org.apache.jorphan.gui.JLabeledTextField;
49
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
50
import org.slf4j.Logger;
51
import org.slf4j.LoggerFactory;
52
53
54
/**
55
 * Implement ResultsRender for XPath tester
56
 */
57
public class RenderAsXPath2 implements ResultRenderer, ActionListener {
58
59
    private static final Logger log = LoggerFactory.getLogger(RenderAsXPath.class);
60
61
    private static final String XPATH_TESTER_COMMAND = "xpath_tester"; // $NON-NLS-1$
62
    
63
    private static final String XPATH_NAMESPACES_COMMAND = "xpath_namespaces"; // $NON-NLS-1$
64
65
    private JPanel xmlWithXPathPane;
66
67
    private JSyntaxTextArea xmlDataField;
68
69
    private JLabeledTextField xpathExpressionField;
70
71
    private JTextArea xpathResultField;
72
73
    private JTabbedPane rightSide;
74
75
    private SampleResult sampleResult = null;
76
    
77
    // Should we return fragment as text, rather than text of fragment?
78
    private final JCheckBox getFragment =
79
        new JCheckBox(JMeterUtils.getResString("xpath_tester_fragment"));//$NON-NLS-1$
80
    
81
    /** {@inheritDoc} */
82
    @Override
83
    public void clearData() {
84
        // N.B. don't set xpathExpressionField to empty to keep xpath
85
        this.xmlDataField.setText(""); // $NON-NLS-1$
86
        this.xpathResultField.setText(""); // $NON-NLS-1$
87
    }
88
89
    /** {@inheritDoc} */
90
    @Override
91
    public void init() {
92
        // Create the panels for the xpath tab
93
        xmlWithXPathPane = createXpathExtractorPanel();
94
    }
95
96
    /**
97
     * Display the response as text or as rendered HTML. Change the text on the
98
     * button appropriate to the current display.
99
     *
100
     * @param e the ActionEvent being processed
101
     */
102
    @Override
103
    public void actionPerformed(ActionEvent e) {
104
        String command = e.getActionCommand();
105
        if ((sampleResult != null) && (XPATH_TESTER_COMMAND.equals(command))) {
106
            String response = xmlDataField.getText();
107
            XPath2Extractor extractor = new XPath2Extractor();
108
            extractor.setFragment(getFragment.isSelected());
109
            executeAndShowXPathTester(response, extractor);
110
        }
111
        else if ((sampleResult != null) && (XPATH_NAMESPACES_COMMAND.equals(command))) {
112
            String response = xmlDataField.getText();
113
            this.xpathResultField.setText(getDocumentNamespaces(response));
114
        }
115
    }
116
117
    /**
118
     * Launch xpath engine to parse a input text
119
     * @param textToParse
120
     */
121
    private void executeAndShowXPathTester(String textToParse, XPath2Extractor extractor) {
122
        if (textToParse != null && textToParse.length() > 0
123
                && this.xpathExpressionField.getText().length() > 0) {
124
            this.xpathResultField.setText(process(textToParse, extractor));
125
            this.xpathResultField.setCaretPosition(0); // go to first line
126
        }
127
    }
128
129
    private String process(String textToParse, XPath2Extractor extractor) {
130
        try {
131
            List<String> matchStrings = new ArrayList<>();
132
            XPathUtil.putValuesForXPathInListUsingSaxon(textToParse, xpathExpressionField.getText(), matchStrings, extractor.getFragment(), -1, getDocumentNamespaces(textToParse));
133
            StringBuilder builder = new StringBuilder();
134
            int nbFound = matchStrings.size();
135
            builder.append("Match count: ").append(nbFound).append("\n");
136
            for (int i = 0; i < nbFound; i++) {
137
                builder.append("Match[").append(i+1).append("]=").append(matchStrings.get(i)).append("\n");
138
            }
139
            return builder.toString();
140
        } catch (Exception e) {
141
            return "Exception:"+ ExceptionUtils.getStackTrace(e);
142
        }
143
    }
144
    
145
    
146
    private String getDocumentNamespaces(String textToParse) {
147
        StringBuilder result = new StringBuilder();
148
        try {
149
            List<String[]> namespaces = XPathUtil.getNamespaces(textToParse);
150
            for (int i = 0;i<namespaces.size();i++) {
151
                result.append(namespaces.get(i)[0])
152
                .append('=') // $NON-NLS-1$
153
                .append(namespaces.get(i)[1])
154
                .append('\n'); // $NON-NLS-1$
155
            }
156
            return result.toString();
157
        } catch (Exception e) {
158
            return "Exception:"+ ExceptionUtils.getStackTrace(e);
159
        }
160
    }
161
    
162
    /*================= internal business =================*/
163
    /** {@inheritDoc} */
164
    @Override
165
    public void renderResult(SampleResult sampleResult) {
166
        String response = ViewResultsFullVisualizer.getResponseAsString(sampleResult);
167
        try {
168
            xmlDataField.setText(response == null ? "" : response);
169
            xmlDataField.setCaretPosition(0);
170
        } catch (Exception e) {
171
            log.error("Exception converting to XML: {}, message: {}", response, e.getMessage(), e);
172
            xmlDataField.setText("Exception converting to XML:"+response+ ", message:"+e.getMessage());
173
            xmlDataField.setCaretPosition(0);
174
        }
175
    }
176
177
    /** {@inheritDoc} */
178
    @Override
179
    public String toString() {
180
        return JMeterUtils.getResString("xpath2_tester"); // $NON-NLS-1$
181
    }
182
183
184
    /** {@inheritDoc} */
185
    @Override
186
    public void setupTabPane() {
187
         // Add xpath tester pane
188
        if (rightSide.indexOfTab(JMeterUtils.getResString("xpath_tester_title")) < 0) { // $NON-NLS-1$
189
            rightSide.addTab(JMeterUtils.getResString("xpath_tester_title"), xmlWithXPathPane); // $NON-NLS-1$
190
        }
191
        clearData();
192
    }
193
194
    /**
195
     * @return XPath Tester panel
196
     */
197
    private JPanel createXpathExtractorPanel() {
198
        xmlDataField = JSyntaxTextArea.getInstance(50, 80, true);
199
        xmlDataField.setCodeFoldingEnabled(true);
200
        xmlDataField.setEditable(false);
201
        xmlDataField.setBracketMatchingEnabled(false);
202
        xmlDataField.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
203
        xmlDataField.setLanguage(SyntaxConstants.SYNTAX_STYLE_XML);
204
        xmlDataField.setLineWrap(true);
205
        xmlDataField.setWrapStyleWord(true);
206
207
        JScrollPane xmlDataPane = JTextScrollPane.getInstance(xmlDataField, true);
208
        xmlDataPane.setPreferredSize(new Dimension(0, 200));
209
210
        JPanel pane = new JPanel(new BorderLayout(0, 5));
211
212
        JSplitPane mainSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
213
                xmlDataPane, createXpathExtractorTasksPanel());
214
        mainSplit.setDividerLocation(0.6d);
215
        mainSplit.setOneTouchExpandable(true);
216
        pane.add(mainSplit, BorderLayout.CENTER);
217
        return pane;
218
    }
219
220
    /**
221
     * Create the XPath task pane
222
     *
223
     * @return XPath task pane
224
     */
225
    private JPanel createXpathExtractorTasksPanel() {
226
        Box xpathActionPanel = Box.createVerticalBox();
227
        
228
        Box selectorAndButton = Box.createHorizontalBox();
229
230
        Border margin = new EmptyBorder(5, 5, 0, 5);
231
        xpathActionPanel.setBorder(margin);
232
        xpathExpressionField = new JLabeledTextField(JMeterUtils.getResString("xpath_tester_field")); // $NON-NLS-1$
233
        
234
        JButton xpathTester = new JButton(JMeterUtils.getResString("xpath_tester_button_test")); // $NON-NLS-1$
235
        xpathTester.setActionCommand(XPATH_TESTER_COMMAND);
236
        xpathTester.addActionListener(this);
237
        
238
        JButton xpathTesterNamespaces = new JButton(JMeterUtils.getResString("xpath_namespaces")); // $NON-NLS-1$
239
        xpathTesterNamespaces.setActionCommand(XPATH_NAMESPACES_COMMAND);
240
        xpathTesterNamespaces.addActionListener(this);
241
        
242
        selectorAndButton.add(xpathExpressionField);
243
        selectorAndButton.add(xpathTester);
244
        selectorAndButton.add(xpathTesterNamespaces);
245
        
246
        xpathActionPanel.add(selectorAndButton);
247
        xpathActionPanel.add(getFragment);
248
        
249
        xpathResultField = new JTextArea();
250
        xpathResultField.setEditable(false);
251
        xpathResultField.setLineWrap(true);
252
        xpathResultField.setWrapStyleWord(true);
253
254
        JPanel xpathTasksPanel = new JPanel(new BorderLayout(0, 5));
255
        xpathTasksPanel.add(xpathActionPanel, BorderLayout.NORTH);
256
        xpathTasksPanel.add(GuiUtils.makeScrollPane(xpathResultField), BorderLayout.CENTER);
257
258
        return xpathTasksPanel;
259
    }
260
261
    /** {@inheritDoc} */
262
    @Override
263
    public synchronized void setRightSide(JTabbedPane side) {
264
        rightSide = side;
265
    }
266
267
    /** {@inheritDoc} */
268
    @Override
269
    public synchronized void setSamplerResult(Object userObject) {
270
        if (userObject instanceof SampleResult) {
271
            sampleResult = (SampleResult) userObject;
272
        }
273
    }
274
275
    /** {@inheritDoc} */
276
    @Override
277
    public void setLastSelectedTab(int index) {
278
        // nothing to do
279
    }
280
281
    /** {@inheritDoc} */
282
    @Override
283
    public void renderImage(SampleResult sampleResult) {
284
        clearData();
285
        xmlDataField.setText(JMeterUtils.getResString("xpath_tester_no_text")); // $NON-NLS-1$
286
    }
287
288
    /** {@inheritDoc} */
289
    @Override
290
    public void setBackgroundColor(Color backGround) {
291
        // NOOP
292
    }
293
}
(-)src/core/org/apache/jmeter/resources/messages.properties (+8 lines)
Lines 1396-1401 Link Here
1396
web_testing_source_ip_device_ipv6=Device IPv6
1396
web_testing_source_ip_device_ipv6=Device IPv6
1397
web_testing_source_ip_hostname=IP/Hostname
1397
web_testing_source_ip_hostname=IP/Hostname
1398
web_testing_title=HTTP Request
1398
web_testing_title=HTTP Request
1399
web_testing_namespaces=namespaces (prefix = value)
1399
while_controller_label=Condition (function or variable)
1400
while_controller_label=Condition (function or variable)
1400
while_controller_title=While Controller
1401
while_controller_title=While Controller
1401
workbench_title=WorkBench
1402
workbench_title=WorkBench
Lines 1423-1431 Link Here
1423
xpath_expression=XPath expression to match against
1424
xpath_expression=XPath expression to match against
1424
xpath_extractor_fragment=Return entire XPath fragment instead of text content?
1425
xpath_extractor_fragment=Return entire XPath fragment instead of text content?
1425
xpath_extractor_query=XPath query:
1426
xpath_extractor_query=XPath query:
1427
xpath_extractor_namespaces=Use every namespaces in the response?
1428
xpath_extractor_user_namespaces=Namespaces list :
1426
xpath_extractor_title=XPath Extractor
1429
xpath_extractor_title=XPath Extractor
1427
xpath_file_file_name=XML file to get values from 
1430
xpath_file_file_name=XML file to get values from 
1428
xpath_tester=XPath Tester
1431
xpath_tester=XPath Tester
1432
xpath2_tester=XPath2 Tester
1433
xpath_namespaces=Show namespaces aliases
1429
xpath_tester_button_test=Test
1434
xpath_tester_button_test=Test
1430
xpath_tester_field=XPath expression
1435
xpath_tester_field=XPath expression
1431
xpath_tester_fragment=Return entire XPath fragment instead of text content?
1436
xpath_tester_fragment=Return entire XPath fragment instead of text content?
Lines 1434-1439 Link Here
1434
xpath_tidy_quiet=Quiet
1439
xpath_tidy_quiet=Quiet
1435
xpath_tidy_report_errors=Report errors
1440
xpath_tidy_report_errors=Report errors
1436
xpath_tidy_show_warnings=Show warnings
1441
xpath_tidy_show_warnings=Show warnings
1442
xpath2_extractor_title=XPath2 Extractor
1443
xpath2_extractor_empty_query=Empty XPath expression !
1444
xpath2_extractor_match_number_failure=MatchNumber out of bonds \:
1437
you_must_enter_a_valid_number=You must enter a valid number
1445
you_must_enter_a_valid_number=You must enter a valid number
1438
zh_cn=Chinese (Simplified)
1446
zh_cn=Chinese (Simplified)
1439
zh_tw=Chinese (Traditional)
1447
zh_tw=Chinese (Traditional)
(-)src/core/org/apache/jmeter/resources/messages_fr.properties (+8 lines)
Lines 1385-1390 Link Here
1385
web_testing_source_ip_device_ipv6=Interface IPv6
1385
web_testing_source_ip_device_ipv6=Interface IPv6
1386
web_testing_source_ip_hostname=IP/Nom d'h\u00F4te
1386
web_testing_source_ip_hostname=IP/Nom d'h\u00F4te
1387
web_testing_title=Requ\u00EAte HTTP
1387
web_testing_title=Requ\u00EAte HTTP
1388
web_testing_namespaces=namespaces (prefix = value)
1388
while_controller_label=Condition (fonction ou variable) \:
1389
while_controller_label=Condition (fonction ou variable) \:
1389
while_controller_title=Contr\u00F4leur Tant Que
1390
while_controller_title=Contr\u00F4leur Tant Que
1390
workbench_title=Plan de travail
1391
workbench_title=Plan de travail
Lines 1412-1420 Link Here
1412
xpath_expression=Expression XPath de correspondance
1413
xpath_expression=Expression XPath de correspondance
1413
xpath_extractor_fragment=Retourner le fragment XPath entier au lieu du contenu
1414
xpath_extractor_fragment=Retourner le fragment XPath entier au lieu du contenu
1414
xpath_extractor_query=Requ\u00EAte XPath \:
1415
xpath_extractor_query=Requ\u00EAte XPath \:
1416
xpath_extractor_namespaces=Utiliser tous les namespaces?
1417
xpath_extractor_user_namespaces=liste des namespaces :
1415
xpath_extractor_title=Extracteur XPath
1418
xpath_extractor_title=Extracteur XPath
1416
xpath_file_file_name=Fichier XML contenant les valeurs
1419
xpath_file_file_name=Fichier XML contenant les valeurs
1417
xpath_tester=Testeur XPath
1420
xpath_tester=Testeur XPath
1421
xpath2_tester=Testeur XPath2
1422
xpath_namespaces=Voir alias namespaces
1418
xpath_tester_button_test=Tester
1423
xpath_tester_button_test=Tester
1419
xpath_tester_field=Expression XPath
1424
xpath_tester_field=Expression XPath
1420
xpath_tester_fragment=Retourner le fragment XPath entier au lieu du contenu ?
1425
xpath_tester_fragment=Retourner le fragment XPath entier au lieu du contenu ?
Lines 1423-1428 Link Here
1423
xpath_tidy_quiet=Silencieux
1428
xpath_tidy_quiet=Silencieux
1424
xpath_tidy_report_errors=Rapporter les erreurs
1429
xpath_tidy_report_errors=Rapporter les erreurs
1425
xpath_tidy_show_warnings=Afficher les alertes
1430
xpath_tidy_show_warnings=Afficher les alertes
1431
xpath2_extractor_title=Extracteur XPath2
1432
xpath2_extractor_empty_query=Expression XPath vide !
1433
xpath2_extractor_match_number_failure=Correspondance hors de port\u00E9e : 
1426
you_must_enter_a_valid_number=Vous devez entrer un nombre valide
1434
you_must_enter_a_valid_number=Vous devez entrer un nombre valide
1427
zh_cn=Chinois (simplifi\u00E9)
1435
zh_cn=Chinois (simplifi\u00E9)
1428
zh_tw=Chinois (traditionnel)
1436
zh_tw=Chinois (traditionnel)
(-)src/core/org/apache/jmeter/util/XPathQueryCacheLoader.java (+60 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.util;
20
21
import java.util.List;
22
23
import org.apache.commons.lang3.tuple.ImmutablePair;
24
import org.slf4j.Logger;
25
import org.slf4j.LoggerFactory;
26
27
import com.github.benmanes.caffeine.cache.CacheLoader;
28
29
import net.sf.saxon.s9api.Processor;
30
import net.sf.saxon.s9api.XPathCompiler;
31
import net.sf.saxon.s9api.XPathExecutable;
32
33
/**
34
 * load method is called when the key composed of
35
 * namespaces + xPathQuery is not in the cache.
36
 * Return the compiled XPathQuery with the associated
37
 * namespaces.
38
 */
39
public class XPathQueryCacheLoader implements CacheLoader<ImmutablePair<String, String>, XPathExecutable> {
40
    
41
    private static final Logger log = LoggerFactory.getLogger(XPathQueryCacheLoader.class);
42
43
    @Override
44
    public XPathExecutable load(ImmutablePair<String, String> key) 
45
            throws Exception {
46
        String xPathQuery = key.left;
47
        String namespacesString = key.right;
48
49
        Processor processor = XPathUtil.getProcessor();
50
        XPathCompiler xPathCompiler = processor.newXPathCompiler();
51
52
        List<String[]> namespacesList = XPathUtil.namespacesParse(namespacesString);
53
        log.debug("Parsed namespaces:{} into list of namespaces:{}", namespacesString, namespacesList);
54
        for (String[] namespaces : namespacesList) {
55
            xPathCompiler.declareNamespace(namespaces[0], namespaces[1]);
56
        }
57
        log.debug("Declared namespaces:{}, now compiling xPathQuery:{}", namespacesList, xPathQuery);
58
        return xPathCompiler.compile(xPathQuery);
59
    }
60
}
(-)src/core/org/apache/jmeter/util/XPathUtil.java (-4 / +178 lines)
Lines 26-36 Link Here
26
import java.io.StringReader;
26
import java.io.StringReader;
27
import java.io.StringWriter;
27
import java.io.StringWriter;
28
import java.nio.charset.StandardCharsets;
28
import java.nio.charset.StandardCharsets;
29
import java.util.ArrayList;
29
import java.util.List;
30
import java.util.List;
30
31
31
import javax.xml.parsers.DocumentBuilder;
32
import javax.xml.parsers.DocumentBuilder;
32
import javax.xml.parsers.DocumentBuilderFactory;
33
import javax.xml.parsers.DocumentBuilderFactory;
33
import javax.xml.parsers.ParserConfigurationException;
34
import javax.xml.parsers.ParserConfigurationException;
35
import javax.xml.stream.FactoryConfigurationError;
36
import javax.xml.stream.XMLInputFactory;
37
import javax.xml.stream.XMLStreamConstants;
38
import javax.xml.stream.XMLStreamException;
39
import javax.xml.stream.XMLStreamReader;
34
import javax.xml.transform.OutputKeys;
40
import javax.xml.transform.OutputKeys;
35
import javax.xml.transform.Source;
41
import javax.xml.transform.Source;
36
import javax.xml.transform.Transformer;
42
import javax.xml.transform.Transformer;
Lines 39-45 Link Here
39
import javax.xml.transform.dom.DOMSource;
45
import javax.xml.transform.dom.DOMSource;
40
import javax.xml.transform.sax.SAXSource;
46
import javax.xml.transform.sax.SAXSource;
41
import javax.xml.transform.stream.StreamResult;
47
import javax.xml.transform.stream.StreamResult;
48
import javax.xml.transform.stream.StreamSource;
42
49
50
import org.apache.commons.lang3.tuple.ImmutablePair;
43
import org.apache.jmeter.assertions.AssertionResult;
51
import org.apache.jmeter.assertions.AssertionResult;
44
import org.apache.xml.utils.PrefixResolver;
52
import org.apache.xml.utils.PrefixResolver;
45
import org.apache.xpath.XPathAPI;
53
import org.apache.xpath.XPathAPI;
Lines 57-72 Link Here
57
import org.xml.sax.SAXException;
65
import org.xml.sax.SAXException;
58
import org.xml.sax.SAXParseException;
66
import org.xml.sax.SAXParseException;
59
67
68
import com.github.benmanes.caffeine.cache.Caffeine;
69
import com.github.benmanes.caffeine.cache.LoadingCache;
70
71
import net.sf.saxon.s9api.Processor;
72
import net.sf.saxon.s9api.SaxonApiException;
73
import net.sf.saxon.s9api.XPathExecutable;
74
import net.sf.saxon.s9api.XPathSelector;
75
import net.sf.saxon.s9api.XdmItem;
76
import net.sf.saxon.s9api.XdmNode;
77
import net.sf.saxon.s9api.XdmValue;
78
60
/**
79
/**
61
 * This class provides a few utility methods for dealing with XML/XPath.
80
 * This class provides a few utility methods for dealing with XML/XPath.
62
 */
81
 */
63
public class XPathUtil {
82
public class XPathUtil {
83
64
    private static final Logger log = LoggerFactory.getLogger(XPathUtil.class);
84
    private static final Logger log = LoggerFactory.getLogger(XPathUtil.class);
65
85
86
    private static final LoadingCache<ImmutablePair<String, String>, XPathExecutable> XPATH_CACHE;
87
    static {
88
        final int cacheSize = JMeterUtils.getPropDefault(
89
                "xpath2query.parser.cache.size", 400);
90
        XPATH_CACHE = Caffeine.newBuilder().maximumSize(cacheSize).build(new XPathQueryCacheLoader());
91
    }
92
93
    /**
94
     * 
95
     */
96
    private static final Processor PROCESSOR = new Processor(false);
97
66
    private XPathUtil() {
98
    private XPathUtil() {
67
        super();
99
        super();
68
    }
100
    }
69
101
102
    public static Processor getProcessor() {
103
        return PROCESSOR;
104
    }
105
70
    private static DocumentBuilderFactory documentBuilderFactory;
106
    private static DocumentBuilderFactory documentBuilderFactory;
71
107
72
    /**
108
    /**
Lines 289-294 Link Here
289
        return sw.toString();
325
        return sw.toString();
290
    }
326
    }
291
    
327
    
328
292
    /**
329
    /**
293
     * @param node {@link Node}
330
     * @param node {@link Node}
294
     * @return String content of node
331
     * @return String content of node
Lines 330-335 Link Here
330
    }
367
    }
331
    
368
    
332
    
369
    
370
333
    /**
371
    /**
334
     * Put in matchStrings results of evaluation
372
     * Put in matchStrings results of evaluation
335
     * @param document XML document
373
     * @param document XML document
Lines 339-348 Link Here
339
     * @param matchNumber match number
377
     * @param matchNumber match number
340
     * @throws TransformerException when the internally used xpath engine fails
378
     * @throws TransformerException when the internally used xpath engine fails
341
     */
379
     */
342
    public static void putValuesForXPathInList(Document document, 
380
    public static void putValuesForXPathInList(Document document, String xPathQuery, List<String> matchStrings, boolean fragment, int matchNumber)
343
            String xPathQuery,
381
            throws TransformerException {
344
            List<String> matchStrings, boolean fragment, 
345
            int matchNumber) throws TransformerException {
346
        String val = null;
382
        String val = null;
347
        XObject xObject = XPathAPI.eval(document, xPathQuery, getPrefixResolver(document));
383
        XObject xObject = XPathAPI.eval(document, xPathQuery, getPrefixResolver(document));
348
        final int objectType = xObject.getType();
384
        final int objectType = xObject.getType();
Lines 381-386 Link Here
381
      }
417
      }
382
    }
418
    }
383
419
420
    public static void putValuesForXPathInListUsingSaxon(
421
            String xmlFile, String xPathQuery, 
422
            List<String> matchStrings, boolean fragment, 
423
            int matchNumber, String namespaces)
424
            throws SaxonApiException, FactoryConfigurationError {
425
426
        // generating the cache key
427
        final ImmutablePair<String, String> key = ImmutablePair.of(xPathQuery, namespaces);
428
429
        //check the cache
430
        XPathExecutable xPathExecutable;
431
        if(!xPathQuery.equals("")) {
432
            xPathExecutable = XPATH_CACHE.get(key);
433
        }
434
        else {
435
            log.warn("Error : {}", JMeterUtils.getResString("xpath2_extractor_empty_query"));
436
            return;
437
        }
438
439
        try (StringReader reader = new StringReader(xmlFile)) {
440
            // We could instanciate it once but might trigger issues in the future 
441
            // Sharing of a DocumentBuilder across multiple threads is not recommended. 
442
            // However, in the current implementation sharing a DocumentBuilder (once initialized) 
443
            // will only cause problems if a SchemaValidator is used.
444
            net.sf.saxon.s9api.DocumentBuilder builder = PROCESSOR.newDocumentBuilder();
445
            XdmNode xdmNode = builder.build(new StreamSource(reader));
446
            
447
            if(xPathExecutable!=null) {
448
                XPathSelector selector = xPathExecutable.load();
449
                selector.setContextItem(xdmNode);
450
                XdmValue nodes = selector.evaluate();
451
                int length = nodes.size();
452
                int indexToMatch = matchNumber;
453
                // In case we need to extract everything
454
                if(matchNumber < 0) {
455
                    for(XdmItem item : nodes) {
456
                        if(fragment) {
457
                            matchStrings.add(item.toString());
458
                        }
459
                        else {
460
                            matchStrings.add(item.getStringValue());
461
                        }
462
                    }
463
                } else {
464
                    if(indexToMatch <= length) {
465
                        if(matchNumber == 0 && length>0) {
466
                            indexToMatch = JMeterUtils.getRandomInt(length)+1;
467
                        } 
468
                        XdmItem item = nodes.itemAt(indexToMatch-1);
469
                        matchStrings.add(fragment ? item.toString() : item.getStringValue());
470
                    } else {
471
                        if(log.isWarnEnabled()) {
472
                            log.warn("Error : {}{}", JMeterUtils.getResString("xpath2_extractor_match_number_failure"),indexToMatch);
473
                        }
474
                    }
475
                }
476
            }
477
        }
478
    }
479
480
481
    public static List<String[]> namespacesParse(String namespaces) {
482
        List<String[]> res = new ArrayList<>();
483
        int length = namespaces.length();
484
        int startWord = 0;
485
        boolean afterEqual = false;
486
        int positionLastKey = -1;
487
        for(int i = 0; i < length; i++) {
488
            char actualChar = namespaces.charAt(i);
489
            if(actualChar=='=' && !afterEqual) {
490
                String [] tmp = new String[2];
491
                tmp[0] = namespaces.substring(startWord, i);
492
                res.add(tmp);
493
                afterEqual = true;
494
                startWord = i+1;
495
                positionLastKey++;
496
            }
497
            else if(namespaces.charAt(i)=='\n' && afterEqual) {
498
                afterEqual = false;
499
                res.get(positionLastKey)[1]= namespaces.substring(startWord, i);
500
                startWord = i+1;
501
            }
502
            else if(namespaces.charAt(i)=='\n') {
503
                startWord = i+1;
504
            }
505
            else if(i==length-1 && afterEqual) {
506
                res.get(positionLastKey)[1]= namespaces.substring(startWord, i+1);
507
            }
508
        }
509
        return res;
510
    }
511
512
    public static List<String[]> getNamespaces(String xml)
513
            throws XMLStreamException, FactoryConfigurationError{
514
        List<String[]> res= new ArrayList<>();
515
        XMLStreamReader reader;
516
        if(!xml.equals("")) {
517
            reader = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xml));
518
            while (reader.hasNext()) {
519
                int event = reader.next();
520
                if (XMLStreamConstants.START_ELEMENT == event) {
521
                    addToList(reader, res);
522
                } else if(XMLStreamConstants.NAMESPACE == event) {
523
                    // This almost never happens
524
                    addToList(reader, res);
525
                }
526
            }
527
        }
528
        return res;
529
    }
530
531
    private static void addToList(XMLStreamReader reader, List<String[]> res) {
532
        boolean isInList = false;
533
        int namespaceCount = reader.getNamespaceCount(); 
534
        if (namespaceCount > 0) {
535
            for (int nsIndex = 0; nsIndex < namespaceCount; nsIndex++) {
536
                String[] tmp = {"",""};
537
                String nsPrefix = reader.getNamespacePrefix(nsIndex);
538
                for(int i = 0;i<res.size();i++) {
539
                    String prefix = res.get(i)[0];
540
                    if(prefix != null && prefix.equals(nsPrefix)) {
541
                        isInList = true;
542
                        break;
543
                    }
544
                }
545
                if(!isInList) {
546
                    String nsId = reader.getNamespaceURI(nsIndex);
547
                    tmp[0] = nsPrefix;
548
                    tmp[1] = nsId;
549
                    res.add(tmp);
550
                }
551
                isInList=false;
552
            }
553
        }
554
    }
555
556
557
384
    /**
558
    /**
385
     * 
559
     * 
386
     * @param document XML Document
560
     * @param document XML Document
(-)test/resources/XPathUtilTestXml.xml (+27 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<Employees>
3
    <Employee id="1">
4
        <age:ag xmlns:age="http://www.w3.org/2003/01/geo/wgs84_pos#">29</age:ag>
5
        <name>Pankaj</name>
6
        <gender>Male</gender>
7
        <role>Java Developer</role>
8
    </Employee>
9
    <Employee id="2">
10
        <age:ag xmlns:age="http://www.w3.org/2003/01/geo/wgs84_pos#">35</age:ag>
11
        <name>Lisa</name>
12
        <gender>Female</gender>
13
        <role>CEO</role>
14
    </Employee>
15
    <Employee id="3">
16
        <age:ag xmlns:age="http://www.w3.org/2003/01/geo/wgs84_pos#">45</age:ag>
17
        <name>Tom</name>
18
        <gender>Male</gender>
19
        <role>Manager</role>
20
    </Employee>
21
    <Employee id="4">
22
        <age:ag xmlns:age="http://www.w3.org/2003/01/geo/wgs84_pos#">55</age:ag>
23
        <name>Meghan</name>
24
        <gender>Female</gender>
25
        <role>Manager</role>
26
    </Employee>
27
</Employees>
(-)test/src/org/apache/jmeter/util/XPathUtilTest.java (-1 / +95 lines)
Lines 18-34 Link Here
18
18
19
package org.apache.jmeter.util;
19
package org.apache.jmeter.util;
20
20
21
import static org.junit.Assert.assertEquals;
21
import static org.junit.Assert.assertThat;
22
import static org.junit.Assert.assertThat;
22
23
23
import java.io.PrintStream;
24
import java.io.PrintStream;
25
import java.util.ArrayList;
26
import java.util.List;
27
28
import javax.xml.stream.FactoryConfigurationError;
24
29
25
import org.hamcrest.CoreMatchers;
30
import org.hamcrest.CoreMatchers;
26
import org.junit.Test;
31
import org.junit.Test;
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
27
34
28
public class XPathUtilTest {
35
import net.sf.saxon.s9api.SaxonApiException;
29
36
37
public class XPathUtilTest {
38
    private static final Logger log = LoggerFactory.getLogger(XPathUtil.class);
30
    final String lineSeparator = System.getProperty("line.separator");
39
    final String lineSeparator = System.getProperty("line.separator");
31
40
41
    final String xmlDoc = JMeterUtils.getResourceFileAsText("XPathUtilTestXml.xml");
42
    
43
    @Test
44
    public void testputValuesForXPathInListUsingSaxon(){
45
        
46
        String xPathQuery="//Employees/Employee/role";
47
        ArrayList<String> matchStrings = new ArrayList<String>();
48
        boolean fragment = false;
49
        String namespaces = "age=http://www.w3.org/2003/01/geo/wgs84_pos#";
50
        int matchNumber = 3;
51
        
52
        try {
53
            XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces);
54
            assertEquals("Manager",matchStrings.get(0));
55
            
56
            matchNumber = 0;
57
            xPathQuery="//Employees/Employee[1]/age:ag";
58
            fragment = true;
59
            matchStrings.clear();
60
            XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces);
61
            assertEquals("<age:ag xmlns:age=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">29</age:ag>",matchStrings.get(0));
62
            assertEquals(1,matchStrings.size());
63
            
64
            matchNumber = -1;
65
            xPathQuery="//Employees/Employee/age:ag";
66
            matchStrings.clear();
67
            XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces);
68
            assertEquals("<age:ag xmlns:age=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">29</age:ag>",matchStrings.get(0));
69
            assertEquals(4,matchStrings.size());
70
            
71
            fragment = false;
72
            matchStrings.clear();
73
            XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces);
74
            assertEquals("29",matchStrings.get(0));
75
            assertEquals(4,matchStrings.size());
76
            
77
            matchStrings.clear();
78
            xPathQuery="regtsgwsdfstgsdf";
79
            XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces);
80
            assertEquals(new ArrayList<String>(),matchStrings);
81
            assertEquals(0,matchStrings.size());
82
            
83
            matchStrings.clear();
84
            xPathQuery="//Employees/Employee[1]/age:ag";
85
            matchNumber = 555;
86
            XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces);
87
            assertEquals(new ArrayList<String>(),matchStrings);
88
            assertEquals(0,matchStrings.size());
89
90
        } catch (SaxonApiException e) {
91
            if (log.isWarnEnabled()) {
92
                log.warn("SaxonApiException while processing ({}). {}", xPathQuery, e.getLocalizedMessage());
93
            }
94
        }catch(FactoryConfigurationError e) {
95
            log.error("FactoryConfigurationError on {}", e);
96
            log.warn("FactoryConfigurationError while processing {}", e.getLocalizedMessage());
97
        }
98
    }
99
100
    @Test
101
    public void testnamespacesParse() {
102
        String namespaces = "donald=duck";
103
        List<String[]> test = XPathUtil.namespacesParse(namespaces);
104
        assertEquals("donald",test.get(0)[0]);
105
        assertEquals("duck",test.get(0)[1]);
106
        
107
        namespaces = "donald=duck\nmickey=mouse";
108
        test = XPathUtil.namespacesParse(namespaces);
109
        assertEquals("donald",test.get(0)[0]);
110
        assertEquals("duck",test.get(0)[1]);
111
        assertEquals("mickey",test.get(1)[0]);
112
        assertEquals("mouse",test.get(1)[1]);
113
        
114
        namespaces = "donald=duck\n\n\nmickey=mouse";
115
        test = XPathUtil.namespacesParse(namespaces);
116
        assertEquals("mickey",test.get(1)[0]);
117
        assertEquals("mouse",test.get(1)[1]);
118
        
119
        namespaces = "geo=patate\n       \n   \n\nmickey=mouse\n\n      \n";
120
        test = XPathUtil.namespacesParse(namespaces);
121
        assertEquals("mickey",test.get(1)[0]);
122
        assertEquals("mouse",test.get(1)[1]);
123
    }
124
32
    @Test
125
    @Test
33
    public void testFormatXmlSimple() {
126
    public void testFormatXmlSimple() {
34
        assertThat(XPathUtil.formatXml("<one foo='bar'>Test</one>"),
127
        assertThat(XPathUtil.formatXml("<one foo='bar'>Test</one>"),
Lines 49-54 Link Here
49
                        "")));
142
                        "")));
50
    }
143
    }
51
144
145
52
    @Test()
146
    @Test()
53
    public void testFormatXmlInvalid() {
147
    public void testFormatXmlInvalid() {
54
        PrintStream origErr = System.err;
148
        PrintStream origErr = System.err;
(-)xdocs/usermanual/component_reference.xml (+52 lines)
Lines 5758-5763 Link Here
5758
</p>
5758
</p>
5759
</component>
5759
</component>
5760
5760
5761
<component name="XPath2 Extractor" index="&sect-num;.8.3"  width="729" height="317" screenshot="xpath2_extractor.png">
5762
    <description>This test element allows the user to extract value(s) from 
5763
        structured response - XML or (X)HTML - using XPath2
5764
        query language.
5765
   </description>
5766
   <properties>
5767
       <property name="Name" required="No">Descriptive name for this element that is shown in the tree.</property>
5768
       <property name="Apply to:" required="Yes">
5769
        This is for use with samplers that can generate sub-samples, 
5770
        e.g. HTTP Sampler with embedded resources, Mail Reader or samples generated by the Transaction Controller.
5771
        <ul>
5772
        <li><code>Main sample only</code> - only applies to the main sample</li>
5773
        <li><code>Sub-samples only</code> - only applies to the sub-samples</li>
5774
        <li><code>Main sample and sub-samples</code> - applies to both.</li>
5775
        <li><code>JMeter Variable Name to use</code> - extraction is to be applied to the contents of the named variable</li>
5776
        </ul>
5777
        XPath matching is applied to all qualifying samples in turn, and all the matching results will be returned.
5778
       </property>
5779
    <property name="Return entire XPath fragment instead of text content?" required="Yes">
5780
    If selected, the fragment will be returned rather than the text content.<br></br>
5781
    For example <code>//title</code> would return "<code>&lt;title&gt;Apache JMeter&lt;/title&gt;</code>" rather than "<code>Apache JMeter</code>".<br></br>
5782
    In this case, <code>//title/text()</code> would return "<code>Apache JMeter</code>".
5783
    </property>
5784
    <property name="Name of created variable" required="Yes">The name of the JMeter variable in which to store the result.</property>
5785
    <property name="XPath Query" required="Yes">Element query in XPath language. Can return more than one match.</property>
5786
    <property name="Match No. (0 for Random)" required="No">If the XPath Path query leads to many results, you can choose which one(s) to extract as Variables:
5787
    <ul>
5788
        <li><code>0</code> : means random</li>
5789
        <li><code>-1</code> means extract all results (default value), they will be named as <code><em>&lt;variable name&gt;</em>_N</code> (where <code>N</code> goes from 1 to Number of results)</li>
5790
        <li><code>X</code> : means extract the X<sup>th</sup> result. If this X<sup>th</sup> is greater than number of matches, then nothing is returned. Default value will be used</li>
5791
    </ul>
5792
    </property>
5793
    <property name="Default Value" required="yes">Default value returned when no match found. 
5794
    It is also returned if the node has no value and the fragment option is not selected.</property>
5795
    <property name="Namespaces list" required="No">List of namespaces aliases you want to use to parse the document.
5796
    You must specify them as follow : <code>prefix=namespace</code>. This implementation makes it easier to
5797
    use namespaces than in the old XPathExtractor version.</property>
5798
   </properties>
5799
   <p>To allow for use in a <complink name="ForEach Controller"/>, it works exactly the same as the above XPath Extractor</p>
5800
   <p>XPath2 Extractor provides some interestings tools such as an improved syntax and much more functions than in it's first version.</p>
5801
   <p>Here are some exemples : </p>
5802
   <dl> 
5803
   <dt><code>abs(/book/page[2])</code></dt>
5804
     <dd>extracts 2<sup>nd</sup> absolute value of the page from a book</dd>
5805
   <dt><code>avg(/librarie/book/page)</code></dt>
5806
     <dd>extracts the average number of page from all the books in the libraries</dd>
5807
     <dt><code>compare(/book[1]/page[2],/book[2]/page[2])</code></dt>
5808
    <dd>return Integer value equal 0 to if the 2<sup>nd</sup> page of the first book is equal to the 2<sup>nd</sup> page of the 2<sup>nd</sup> book, else return -1.</dd>
5809
 </dl>
5810
 <p>To see more informations about thoses fuctions, please check <a href="http://saxon.sourceforge.net/saxon7.9.1/functions.html">xPath2 functions</a></p>
5811
</component>
5812
5761
<component name="XPath Extractor" index="&sect-num;.8.3"  width="729" height="317" screenshot="xpath_extractor.png">
5813
<component name="XPath Extractor" index="&sect-num;.8.3"  width="729" height="317" screenshot="xpath_extractor.png">
5762
    <description>This test element allows the user to extract value(s) from 
5814
    <description>This test element allows the user to extract value(s) from 
5763
        structured response - XML or (X)HTML - using XPath
5815
        structured response - XML or (X)HTML - using XPath

Return to bug 60991