You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2012/12/16 16:34:58 UTC

svn commit: r1422599 - in /jmeter/trunk: ./ res/maven/ src/components/org/apache/jmeter/extractor/ src/components/org/apache/jmeter/extractor/gui/ src/core/org/apache/jmeter/resources/ xdocs/

Author: pmouawad
Date: Sun Dec 16 15:34:56 2012
New Revision: 1422599

URL: http://svn.apache.org/viewvc?rev=1422599&view=rev
Log:
Bug 54259 - Introduce a CSS or jquery-like based Extractor
Bugzilla Id: 54259

Added:
    jmeter/trunk/src/components/org/apache/jmeter/extractor/Extractor.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/extractor/HtmlExtractor.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/extractor/JSoupExtractor.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/extractor/JoddExtractor.java   (with props)
    jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/HtmlExtractorGui.java   (with props)
Modified:
    jmeter/trunk/LICENSE
    jmeter/trunk/build.properties
    jmeter/trunk/build.xml
    jmeter/trunk/eclipse.classpath
    jmeter/trunk/res/maven/ApacheJMeter_parent.pom
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/xdocs/changes.xml

Modified: jmeter/trunk/LICENSE
URL: http://svn.apache.org/viewvc/jmeter/trunk/LICENSE?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/LICENSE [utf-8] (original)
+++ jmeter/trunk/LICENSE [utf-8] Sun Dec 16 15:34:56 2012
@@ -1517,6 +1517,100 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAG
 
 ################################################################################
 
+Jodd-3.4.0
+====
+
+Jodd license (BSD License)
+
+Copyright (c) 2003-2012, Jodd Team
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+Neither the name of the Jodd nor the names of its contributors
+may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+
+JSOUP 1.7.1
+====
+
+jsoup License (MIT License)
+
+The jsoup code-base (include source and compiled packages) are 
+distributed under the open source MIT license as described below.
+The MIT License
+
+Copyright � 2009 - 2012 Jonathan Hedley (jonathan@hedley.net)
+
+Permission is hereby granted, free of charge, to any person obtaining a 
+copy of this software and associated documentation files (the "Software"), 
+to deal in the Software without restriction, including without limitation the 
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
+sell copies of the Software, and to permit persons to whom the Software is 
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in 
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+################################################################################
+
+slf4j-api-1.7.2
+====
+
+MIT license.
+
+Copyright (c) 2004-2011 QOS.ch All rights reserved. Permission is hereby 
+granted, free of charge, to any person obtaining a copy of this software
+and associated documentation files (the "Software"), to deal in the Software 
+without restriction, including without limitation the rights to use, copy, 
+modify, merge, publish, distribute, sublicense, and/or sell copies of the 
+Software, and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions: The above copyright notice and this 
+permission notice shall be included in all copies or substantial portions 
+of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+################################################################################
+
 XStream v1.4.2
 =======
 

Modified: jmeter/trunk/build.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/build.properties?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/build.properties (original)
+++ jmeter/trunk/build.properties Sun Dec 16 15:34:56 2012
@@ -188,6 +188,21 @@ js_rhino.jar                = rhino-${js
 js_rhino.loc                = ${maven2.repo}/org/mozilla/rhino/${js_rhino.version}
 js_rhino.md5                = 3850097fb5c9aa1065cc198f1b82dcf1
 
+jodd-core.version			= 3.4.0
+jodd-core.jar				= jodd-core-${jodd-core.version}.jar
+jodd-core.loc            	= ${maven2.repo}/org/jodd/jodd-core/${jodd-core.version}
+jodd-core.md5            	= 3c65b95f898236380fc9db0d2476ba12
+
+jodd-lagarto.version		= 3.4.0
+jodd-lagarto.jar			= jodd-lagarto-${jodd-lagarto.version}.jar
+jodd-lagarto.loc            = ${maven2.repo}/org/jodd/jodd-lagarto/${jodd-lagarto.version}
+jodd-lagarto.md5            = 78c175f98d35c361971cd37997e18c1d
+
+jsoup.version				= 1.7.1
+jsoup.jar					= jsoup-${jsoup.version}.jar
+jsoup.loc                	= ${maven2.repo}/org/jsoup/jsoup/${jsoup.version}
+jsoup.md5             		= d2be2edd503a224a7357ff39b8be57f1
+
 junit.version               = 4.10
 junit.jar                   = junit-${junit.version}.jar
 junit.loc                   = ${maven2.repo}/junit/junit/${junit.version}
@@ -198,6 +213,11 @@ logkit.jar                  = logkit-${l
 logkit.loc                  = ${maven2.repo}/logkit/logkit/${logkit.version}
 logkit.md5                  = 8D82A3E91AAE216D0A2A40B837A232FF
 
+slf4j-api.version           = 1.7.2
+slf4j-api.jar               = slf4j-api-${slf4j-api.version}.jar
+slf4j-api.loc               = ${maven2.repo}/org/slf4j/slf4j-api/${slf4j-api.version}
+slf4j-api.md5               = 21216c2ee1bf4f097a51e49418527100
+
 soap.version                = 2.3.1
 soap.jar                    = soap-${soap.version}.jar
 soap.loc                    = ${maven2.repo}/soap/soap/${soap.version}

Modified: jmeter/trunk/build.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/build.xml?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/build.xml (original)
+++ jmeter/trunk/build.xml Sun Dec 16 15:34:56 2012
@@ -376,9 +376,13 @@
     <include name="${lib.dir}/${jdom.jar}"/>
     <include name="${lib.dir}/${jms.jar}"/>
     <include name="${lib.dir}/${js_rhino.jar}"/>
+  	<include name="${lib.dir}/${jodd-core.jar}"/>
+  	<include name="${lib.dir}/${jodd-lagarto.jar}"/>
+    <include name="${lib.dir}/${jsoup.jar}"/>
     <include name="${lib.dir}/${junit.jar}"/>
     <include name="${lib.dir}/${logkit.jar}"/>
     <include name="${lib.dir}/${serializer.jar}"/>
+    <include name="${lib.dir}/${slf4j-api.jar}"/>
     <include name="${lib.dir}/${soap.jar}"/>
     <include name="${lib.dir}/${tidy.jar}"/>
     <include name="${lib.dir}/${tika-core.jar}"/>
@@ -439,9 +443,13 @@
     <pathelement location="${lib.dir}/${jdom.jar}"/>
     <pathelement location="${lib.dir}/${jms.jar}"/>
     <pathelement location="${lib.dir}/${js_rhino.jar}"/>
+  	<pathelement location="${lib.dir}/${jodd-core.jar}"/>
+    <pathelement location="${lib.dir}/${jodd-lagarto.jar}"/>
+    <pathelement location="${lib.dir}/${jsoup.jar}"/>
     <pathelement location="${lib.dir}/${junit.jar}"/>
     <pathelement location="${lib.dir}/${logkit.jar}"/>
     <pathelement location="${lib.dir}/${serializer.jar}"/>
+    <pathelement location="${lib.dir}/${slf4j-api.jar}"/>
     <pathelement location="${lib.dir}/${soap.jar}"/>
     <pathelement location="${lib.dir}/${tidy.jar}"/>
     <pathelement location="${lib.dir}/${tika-core.jar}"/>
@@ -2714,9 +2722,13 @@ run JMeter unless all the JMeter jars ar
         <process_jarfile jarname="jdom"/>
         <process_jarfile jarname="jms"/>
         <process_jarfile jarname="js_rhino"/>
+    	<process_jarfile jarname="jodd-core"/>
+        <process_jarfile jarname="jodd-lagarto"/>
+        <process_jarfile jarname="jsoup"/>
         <process_jarfile jarname="junit"/>
         <process_jarfile jarname="logkit"/>
         <process_jarfile jarname="serializer"/>
+    	<process_jarfile jarname="slf4j-api"/>
         <process_jarfile jarname="soap"/>
         <process_jarfile jarname="tidy"/>
         <process_jarfile jarname="tika-core"/>

Modified: jmeter/trunk/eclipse.classpath
URL: http://svn.apache.org/viewvc/jmeter/trunk/eclipse.classpath?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/eclipse.classpath (original)
+++ jmeter/trunk/eclipse.classpath Sun Dec 16 15:34:56 2012
@@ -67,12 +67,16 @@
 	<classpathentry kind="lib" path="lib/jcharts-0.7.5.jar"/>
 	<classpathentry kind="lib" path="lib/jdom-1.1.2.jar"/>
 	<classpathentry kind="lib" path="lib/rhino-1.7R4.jar"/>
+	<classpathentry kind="lib" path="lib/jodd-core-3.4.0.jar"/>
+	<classpathentry kind="lib" path="lib/jodd-lagarto-3.4.0.jar"/>
+	<classpathentry kind="lib" path="lib/jsoup-1.7.1.jar"/>
     <classpathentry kind="lib" path="lib/jtidy-r938.jar"/>
     <classpathentry kind="lib" path="lib/junit-4.10.jar"/>
 	<classpathentry kind="lib" path="lib/logkit-2.0.jar"/>
 	<classpathentry kind="lib" path="lib/mail-1.4.4.jar"/>
 	<classpathentry kind="lib" path="lib/oro-2.0.8.jar"/>
 	<classpathentry kind="lib" path="lib/serializer-2.7.1.jar"/>
+    <classpathentry kind="lib" path="lib/slf4j-api-1.7.2.jar"/>
 	<classpathentry kind="lib" path="lib/soap-2.3.1.jar"/>
     <classpathentry kind="lib" path="lib/tika-core-1.2.jar"/>
     <classpathentry kind="lib" path="lib/tika-parsers-1.2.jar"/>

Modified: jmeter/trunk/res/maven/ApacheJMeter_parent.pom
URL: http://svn.apache.org/viewvc/jmeter/trunk/res/maven/ApacheJMeter_parent.pom?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/res/maven/ApacheJMeter_parent.pom (original)
+++ jmeter/trunk/res/maven/ApacheJMeter_parent.pom Sun Dec 16 15:34:56 2012
@@ -77,9 +77,12 @@ under the License.
       <jakarta-oro.version>2.0.8</jakarta-oro.version>
       <jcharts.version>0.7.5</jcharts.version>
       <jdom.version>1.1.2</jdom.version>
+      <jodd.version>3.4.0</jodd.version>
+      <jsoup.version>1.7.1</jsoup.version>
       <js_rhino.version>1.7R4</js_rhino.version>
       <junit.version>4.10</junit.version>
       <logkit.version>2.0</logkit.version>
+      <slf4j.version>1.7.2</slf4j.version>
       <soap.version>2.3.1</soap.version>
       <tidy.version>r938</tidy.version>
       <xmlpull.version>1.1.3.1</xmlpull.version>
@@ -314,6 +317,26 @@ under the License.
         <artifactId>geronimo-jms_1.1_spec</artifactId>
         <version>${jms.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.jsoup</groupId>
+        <artifactId>jsoup</artifactId>
+        <version>${jsoup.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jodd</groupId>
+        <artifactId>jodd-core</artifactId>
+        <version>${jodd.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jodd</groupId>
+        <artifactId>jodd-lagarto</artifactId>
+        <version>${jodd.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>${slf4j.version}</version>
+      </dependency>
       <!-- Docs only; not needed for source or binary archives 
       <dependency>
         <groupId>org.apache.velocity</groupId>

Added: jmeter/trunk/src/components/org/apache/jmeter/extractor/Extractor.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/extractor/Extractor.java?rev=1422599&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/extractor/Extractor.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/extractor/Extractor.java Sun Dec 16 15:34:56 2012
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.jmeter.extractor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * CSS/JQuery based extractor for HTML pages
+ * @since 2.9
+ */
+public interface Extractor extends Serializable {
+    /**
+     * 
+     * @param expression Expression used for extraction of nodes
+     * @param attribute Attribute name to return 
+     * @param matchNumber Match number
+     * @param inputString Page or excerpt
+     * @param result List<String> results
+     * @param found current matches found
+     * @param cacheIfPossible Cache analysis if possibler
+     * @return match found updated
+     */
+    int extract(
+            String expression,
+            String attribute,
+            int matchNumber, 
+            String inputString, 
+            List<String> result,
+            int found,
+            boolean cacheIfPossible);
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/extractor/Extractor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/extractor/HtmlExtractor.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/extractor/HtmlExtractor.java?rev=1422599&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/extractor/HtmlExtractor.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/extractor/HtmlExtractor.java Sun Dec 16 15:34:56 2012
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.extractor;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jmeter.processor.PostProcessor;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.AbstractScopedTestElement;
+import org.apache.jmeter.testelement.property.IntegerProperty;
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterVariables;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * 
+ */
+public class HtmlExtractor extends AbstractScopedTestElement implements PostProcessor, Serializable {
+
+    public static final String EXTRACTOR_JSOUP = "JSOUP"; //$NON-NLS-1$
+
+    public static final String EXTRACTOR_JODD = "JODD"; //$NON-NLS-1$
+
+    public static String[] getImplementations(){
+        return new String[]{EXTRACTOR_JSOUP,EXTRACTOR_JODD};
+    }
+
+    public static final String DEFAULT_EXTRACTOR = ""; // $NON-NLS-1$
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 3978073849365558131L;
+
+    private static final Logger log = LoggingManager.getLoggerForClass();
+
+    private static final String EXPRESSION = "HtmlExtractor.expr"; // $NON-NLS-1$
+
+    private static final String ATTRIBUTE = "HtmlExtractor.attribute"; // $NON-NLS-1$
+
+    private static final String REFNAME = "HtmlExtractor.refname"; // $NON-NLS-1$
+
+    private static final String MATCH_NUMBER = "HtmlExtractor.match_number"; // $NON-NLS-1$
+
+    private static final String DEFAULT = "HtmlExtractor.default"; // $NON-NLS-1$
+
+    private static final String EXTRACTOR_IMPL = "HtmlExtractor.extractor_impl"; // $NON-NLS-1$
+
+    private static final String REF_MATCH_NR = "_matchNr"; // $NON-NLS-1$
+    
+    private static final String UNDERSCORE = "_";  // $NON-NLS-1$
+    
+    private Extractor extractor;
+
+    /**
+     * Parses the response data using CSS/JQuery expressions and saving the results
+     * into variables for use later in the test.
+     *
+     * @see org.apache.jmeter.processor.PostProcessor#process()
+     */
+    @Override
+    public void process() {
+        JMeterContext context = getThreadContext();
+        SampleResult previousResult = context.getPreviousResult();
+        if (previousResult == null) {
+            return;
+        }
+        log.debug("HtmlExtractor processing result");
+
+        // Fetch some variables
+        JMeterVariables vars = context.getVariables();
+        
+        String refName = getRefName();
+        String expression = getExpression();
+        String attribute = getAttribute();
+        int matchNumber = getMatchNumber();
+        final String defaultValue = getDefaultValue();
+        
+        if (defaultValue.length() > 0){// Only replace default if it is provided
+            vars.put(refName, defaultValue);
+        }
+        
+        try {            
+            List<String> matches = 
+                    extractMatchingStrings(vars, expression, attribute, matchNumber, previousResult);
+            int prevCount = 0;
+            String prevString = vars.get(refName + REF_MATCH_NR);
+            if (prevString != null) {
+                vars.remove(refName + REF_MATCH_NR);// ensure old value is not left defined
+                try {
+                    prevCount = Integer.parseInt(prevString);
+                } catch (NumberFormatException e1) {
+                    log.warn("Could not parse "+prevString+" "+e1);
+                }
+            }
+            int matchCount=0;// Number of refName_n variable sets to keep
+            try {
+                String match;
+                if (matchNumber >= 0) {// Original match behaviour
+                    match = getCorrectMatch(matches, matchNumber);
+                    if (match != null) {
+                        vars.put(refName, match);
+                    } 
+                } else // < 0 means we save all the matches
+                {
+                    matchCount = matches.size();
+                    vars.put(refName + REF_MATCH_NR, Integer.toString(matchCount));// Save the count
+                    for (int i = 1; i <= matchCount; i++) {
+                        match = getCorrectMatch(matches, i);
+                        if (match != null) {
+                            final String refName_n = new StringBuilder(refName).append(UNDERSCORE).append(i).toString();
+                            vars.put(refName_n, match);
+                        }
+                    }
+                }
+                // Remove any left-over variables
+                for (int i = matchCount + 1; i <= prevCount; i++) {
+                    final String refName_n = new StringBuilder(refName).append(UNDERSCORE).append(i).toString();
+                    vars.remove(refName_n);
+                }
+            } catch (RuntimeException e) {
+                log.warn("Error while generating result");
+            }
+
+        } catch (RuntimeException e) {
+            log.warn("Error while generating result");
+        }
+
+    }
+
+    /**
+     * Grab the appropriate result from the list.
+     *
+     * @param matches
+     *            list of matches
+     * @param entry
+     *            the entry number in the list
+     * @return MatchResult
+     */
+    private String getCorrectMatch(List<String> matches, int entry) {
+        int matchSize = matches.size();
+
+        if (matchSize <= 0 || entry > matchSize){
+            return null;
+        }
+
+        if (entry == 0) // Random match
+        {
+            return matches.get(JMeterUtils.getRandomInt(matchSize));
+        }
+
+        return matches.get(entry - 1);
+    }
+
+    private List<String> extractMatchingStrings(JMeterVariables vars,
+            String expression, String attribute, int matchNumber,
+            SampleResult previousResult) {
+        int found = 0;
+        List<String> result = new ArrayList<String>();
+        if (isScopeVariable()){
+            String inputString=vars.get(getVariableName());
+            getExtractorImpl().extract(expression, attribute, matchNumber, inputString, result, found, true);
+        } else {
+            List<SampleResult> sampleList = getSampleList(previousResult);
+            int i=0;
+            for (SampleResult sr : sampleList) {
+                String inputString = sr.getResponseDataAsString();
+                found = getExtractorImpl().extract(expression, attribute, matchNumber, inputString, result, found, i==0);
+                i++;
+                if (matchNumber > 0 && found == matchNumber){// no need to process further
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+    
+    /**
+     * 
+     * @return Extractor
+     */
+    private Extractor getExtractorImpl() {
+        if (extractor == null) {
+            boolean useDefaultExtractor = DEFAULT_EXTRACTOR.equals(getExtractor());
+            if (useDefaultExtractor || EXTRACTOR_JSOUP.equals(getExtractor())) {
+                extractor = new JSoupExtractor();
+            } else if (EXTRACTOR_JODD.equals(getExtractor())) {
+                extractor = new JSoupExtractor();
+            } else {
+                throw new IllegalArgumentException("Extractor implementation:"+ getExtractor()+" is unknown");
+            }
+        }
+        return extractor;
+    }
+    
+
+    public void setExtractor(String attribute) {
+        setProperty(EXTRACTOR_IMPL, attribute);
+    }
+
+    public String getExtractor() {
+        return getPropertyAsString(EXTRACTOR_IMPL); // $NON-NLS-1$
+    }
+
+    
+    public void setAttribute(String attribute) {
+        setProperty(ATTRIBUTE, attribute);
+    }
+
+    public String getAttribute() {
+        return getPropertyAsString(ATTRIBUTE, ""); // $NON-NLS-1$
+    }
+
+    public void setExpression(String regex) {
+        setProperty(EXPRESSION, regex);
+    }
+
+    public String getExpression() {
+        return getPropertyAsString(EXPRESSION);
+    }
+
+    public void setRefName(String refName) {
+        setProperty(REFNAME, refName);
+    }
+
+    public String getRefName() {
+        return getPropertyAsString(REFNAME);
+    }
+
+    /**
+     * Set which Match to use. This can be any positive number, indicating the
+     * exact match to use, or 0, which is interpreted as meaning random.
+     *
+     * @param matchNumber
+     */
+    public void setMatchNumber(int matchNumber) {
+        setProperty(new IntegerProperty(MATCH_NUMBER, matchNumber));
+    }
+
+    public void setMatchNumber(String matchNumber) {
+        setProperty(MATCH_NUMBER, matchNumber);
+    }
+
+    public int getMatchNumber() {
+        return getPropertyAsInt(MATCH_NUMBER);
+    }
+
+    public String getMatchNumberAsString() {
+        return getPropertyAsString(MATCH_NUMBER);
+    }
+
+    /**
+     * Sets the value of the variable if no matches are found
+     *
+     * @param defaultValue
+     */
+    public void setDefaultValue(String defaultValue) {
+        setProperty(DEFAULT, defaultValue);
+    }
+
+    public String getDefaultValue() {
+        return getPropertyAsString(DEFAULT);
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/extractor/HtmlExtractor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/extractor/JSoupExtractor.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/extractor/JSoupExtractor.java?rev=1422599&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/extractor/JSoupExtractor.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/extractor/JSoupExtractor.java Sun Dec 16 15:34:56 2012
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.jmeter.extractor;
+
+import java.util.List;
+
+import org.apache.jorphan.util.JOrphanUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
+/**
+ * JSoup based CSS/JQuery extractor
+ * @see http://jsoup.org/cookbook/extracting-data/selector-syntax
+ * @since 2.9
+ */
+public class JSoupExtractor implements Extractor {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -6308012192067714191L;
+
+
+    /**
+     * 
+     */
+    public JSoupExtractor() {
+        super();
+    }
+
+    /**
+     * @see org.apache.jmeter.extractor.Extractor#extract(java.lang.String, java.lang.String, int, java.lang.String, java.util.List, int, boolean)
+     */
+    @Override
+    public int extract(String expression, String attribute, int matchNumber,
+            String inputString, List<String> result, int found,
+            boolean cacheIfPossible) {
+        Document document = Jsoup.parse(inputString);
+        Elements elements = document.select(expression);
+        int size = elements.size();
+        for (int i = 0; i < size; i++) {
+            Element element = elements.get(i);
+            if (matchNumber <=0 || found != matchNumber) {
+                result.add(extractValue(attribute, element));
+                found++;
+            } else {
+                break;
+            }
+        }
+        return found;
+    }
+    
+    
+    /**
+     * 
+     * @param attribute Attribute to extract
+     * @param element Element
+     * @return String value
+     */
+    private String extractValue(String attribute, Element element) {
+        if (!JOrphanUtils.isBlank(attribute)) {
+            return element.attr(attribute);
+        } else {
+            return element.text().trim();
+        }
+    }
+}
\ No newline at end of file

Propchange: jmeter/trunk/src/components/org/apache/jmeter/extractor/JSoupExtractor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/extractor/JoddExtractor.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/extractor/JoddExtractor.java?rev=1422599&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/extractor/JoddExtractor.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/extractor/JoddExtractor.java Sun Dec 16 15:34:56 2012
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.jmeter.extractor;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import jodd.lagarto.dom.LagartoDOMBuilder;
+import jodd.lagarto.dom.Node;
+import jodd.lagarto.dom.NodeSelector;
+
+import org.apache.jorphan.util.JOrphanUtils;
+
+/**
+ * Jodd-Lagerto based CSS/JQuery extractor
+ * @see http://jodd.org/doc/csselly/
+ * @since 2.9
+ */
+public class JoddExtractor implements Extractor {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -7235814605293262972L;
+
+
+    /**
+     * 
+     */
+    public JoddExtractor() {
+        super();
+    }
+
+    /**
+     * @see org.apache.jmeter.extractor.Extractor#extract(java.lang.String, java.lang.String, int, java.lang.String, java.util.List, int, boolean)
+     */
+    @Override
+    public int extract(String expression, String attribute, int matchNumber,
+            String inputString, List<String> result, int found,
+            boolean cacheIfPossible) {
+        LagartoDOMBuilder domBuilder = new LagartoDOMBuilder();
+        jodd.lagarto.dom.Document doc = domBuilder.parse(inputString);
+        NodeSelector nodeSelector = new NodeSelector(doc);
+        LinkedList<Node> elements = nodeSelector.select(expression);
+        int size = elements.size();
+        for (int i = 0; i < size; i++) {
+            Node element = elements.get(i);
+            if (matchNumber <=0 || found != matchNumber) {
+                result.add(extractValue(attribute, element));
+                found++;
+            } else {
+                break;
+            }
+        }
+        
+        return found;
+    }
+    
+    
+    private String extractValue(String attribute, Node element) {
+        if (!JOrphanUtils.isBlank(attribute)) {
+            return element.getAttribute(attribute);
+        } else {
+            return element.getTextContent().trim();
+        }
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/extractor/JoddExtractor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/HtmlExtractorGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/HtmlExtractorGui.java?rev=1422599&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/HtmlExtractorGui.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/HtmlExtractorGui.java Sun Dec 16 15:34:56 2012
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.extractor.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.apache.jmeter.extractor.HtmlExtractor;
+import org.apache.jmeter.gui.util.HorizontalPanel;
+import org.apache.jmeter.processor.gui.AbstractPostProcessorGui;
+import org.apache.jmeter.testelement.AbstractScopedTestElement;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.gui.JLabeledTextField;
+
+/**
+ * CSS/JQuery Expression Extractor Post-Processor GUI
+ * @since 2.9
+ */
+public class HtmlExtractorGui extends AbstractPostProcessorGui {
+    private static final long serialVersionUID = 240L;
+
+    /**
+     * This choice means don't explicitly set Implementation and rely on default
+     */
+    private static final String USE_DEFAULT_EXTRACTOR_IMPL = ""; // $NON-NLS-1$
+
+    private JLabeledTextField expressionField;
+
+    private JLabeledTextField attributeField;
+    
+    private JLabeledTextField defaultField;
+
+    private JLabeledTextField matchNumberField;
+
+    private JLabeledTextField refNameField;
+
+    private JComboBox extractorImplName;
+
+
+    public HtmlExtractorGui() {
+        super();
+        init();
+    }
+
+    @Override
+    public String getLabelResource() {
+        return "html_extractor_title"; //$NON-NLS-1$
+    }
+
+    @Override
+    public void configure(TestElement el) {
+        super.configure(el);
+        if (el instanceof HtmlExtractor){
+            HtmlExtractor htmlExtractor = (HtmlExtractor) el;
+            showScopeSettings(htmlExtractor, true);
+            expressionField.setText(htmlExtractor.getExpression());
+            attributeField.setText(htmlExtractor.getAttribute());
+            defaultField.setText(htmlExtractor.getDefaultValue());
+            matchNumberField.setText(htmlExtractor.getMatchNumberAsString());
+            refNameField.setText(htmlExtractor.getRefName());
+            extractorImplName.setSelectedItem(htmlExtractor.getExtractor());
+        }
+    }
+
+    /**
+     * @see org.apache.jmeter.gui.JMeterGUIComponent#createTestElement()
+     */
+    @Override
+    public TestElement createTestElement() {
+        AbstractScopedTestElement extractor = new HtmlExtractor();
+        modifyTestElement(extractor);
+        return extractor;
+    }
+
+    /**
+     * Modifies a given TestElement to mirror the data in the gui components.
+     *
+     * @see org.apache.jmeter.gui.JMeterGUIComponent#modifyTestElement(TestElement)
+     */
+    @Override
+    public void modifyTestElement(TestElement extractor) {
+        super.configureTestElement(extractor);
+        if (extractor instanceof HtmlExtractor) {
+            HtmlExtractor htmlExtractor = (HtmlExtractor) extractor;
+            saveScopeSettings(htmlExtractor);
+            htmlExtractor.setRefName(refNameField.getText());
+            htmlExtractor.setExpression(expressionField.getText());
+            htmlExtractor.setAttribute(attributeField.getText());
+            htmlExtractor.setDefaultValue(defaultField.getText());
+            htmlExtractor.setMatchNumber(matchNumberField.getText());
+            if(extractorImplName.getSelectedIndex()< HtmlExtractor.getImplementations().length) {
+                htmlExtractor.setExtractor(HtmlExtractor.getImplementations()[extractorImplName.getSelectedIndex()]);
+            } else {
+                htmlExtractor.setExtractor(USE_DEFAULT_EXTRACTOR_IMPL);               
+            }
+
+        }
+    }
+
+    /**
+     * Implements JMeterGUIComponent.clearGui
+     */
+    @Override
+    public void clearGui() {
+        super.clearGui();
+        extractorImplName.setSelectedItem(HtmlExtractor.DEFAULT_EXTRACTOR);
+        expressionField.setText(""); //$NON-NLS-1$        
+        attributeField.setText(""); //$NON-NLS-1$
+        defaultField.setText(""); //$NON-NLS-1$
+        refNameField.setText(""); //$NON-NLS-1$
+        matchNumberField.setText(""); //$NON-NLS-1$
+    }
+
+    private void init() {
+        setLayout(new BorderLayout());
+        setBorder(makeBorder());
+
+        Box box = Box.createVerticalBox();
+        box.add(makeTitlePanel());
+        box.add(createScopePanel(true));
+        box.add(makeExtractorPanel());
+        add(box, BorderLayout.NORTH);
+        add(makeParameterPanel(), BorderLayout.CENTER);
+    }
+
+    
+
+    private Component makeExtractorPanel() {
+        JPanel panel = new HorizontalPanel();
+        panel.setBorder(BorderFactory.createTitledBorder(JMeterUtils.getResString("html_extractor_type"))); //$NON-NLS-1$
+        
+        DefaultComboBoxModel m = new DefaultComboBoxModel();
+        for (String s : HtmlExtractor.getImplementations()){
+            m.addElement(s);
+        }
+        m.addElement(USE_DEFAULT_EXTRACTOR_IMPL);
+        extractorImplName = new JComboBox(m);
+        extractorImplName.setSelectedItem(HtmlExtractor.DEFAULT_EXTRACTOR);
+        JLabel label2 = new JLabel(JMeterUtils.getResString("extractor_type")); // $NON-NLS-1$
+        label2.setLabelFor(extractorImplName);
+        panel.add(label2);
+        panel.add(extractorImplName);
+        return panel;
+    }
+
+    private JPanel makeParameterPanel() {        
+        expressionField = new JLabeledTextField(JMeterUtils.getResString("expression_field")); //$NON-NLS-1$
+        attributeField = new JLabeledTextField(JMeterUtils.getResString("attribute_field")); //$NON-NLS-1$
+        defaultField = new JLabeledTextField(JMeterUtils.getResString("default_value_field")); //$NON-NLS-1$
+        refNameField = new JLabeledTextField(JMeterUtils.getResString("ref_name_field")); //$NON-NLS-1$
+        matchNumberField = new JLabeledTextField(JMeterUtils.getResString("match_num_field")); //$NON-NLS-1$
+
+        JPanel panel = new JPanel(new GridBagLayout());
+        GridBagConstraints gbc = new GridBagConstraints();
+        initConstraints(gbc);
+        addField(panel, refNameField, gbc);
+        resetContraints(gbc);
+        addField(panel, expressionField, gbc);
+        resetContraints(gbc);
+        addField(panel, attributeField, gbc);
+        resetContraints(gbc);
+        addField(panel, matchNumberField, gbc);
+        resetContraints(gbc);
+        gbc.weighty = 1;
+        addField(panel, defaultField, gbc);
+        return panel;
+    }
+
+    private void addField(JPanel panel, JLabeledTextField field, GridBagConstraints gbc) {
+        List<JComponent> item = field.getComponentList();
+        panel.add(item.get(0), gbc.clone());
+        gbc.gridx++;
+        gbc.weightx = 1;
+        gbc.fill=GridBagConstraints.HORIZONTAL;
+        panel.add(item.get(1), gbc.clone());
+    }
+
+    // Next line
+    private void resetContraints(GridBagConstraints gbc) {
+        gbc.gridx = 0;
+        gbc.gridy++;
+        gbc.weightx = 0;
+        gbc.fill=GridBagConstraints.NONE;
+    }
+
+    private void initConstraints(GridBagConstraints gbc) {
+        gbc.anchor = GridBagConstraints.NORTHWEST;
+        gbc.fill = GridBagConstraints.NONE;
+        gbc.gridheight = 1;
+        gbc.gridwidth = 1;
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 0;
+        gbc.weighty = 0;
+    }
+}

Propchange: jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/HtmlExtractorGui.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sun Dec 16 15:34:56 2012
@@ -119,6 +119,7 @@ assertion_title=Response Assertion
 assertion_url_samp=URL Sampled
 assertion_visualizer_title=Assertion Results
 attribute=Attribute
+attribute_field=Attribute \:
 attrs=Attributes
 auth_base_url=Base URL
 auth_manager_title=HTTP Authorization Manager
@@ -267,6 +268,7 @@ exit=Exit
 expand=Expand
 expected_return_code_title=Expected Return Code: 
 expiration=Expiration
+expression_field=CSS/JQuery expression \:
 field_name=Field name
 file=File
 file_already_in_use=That file is already in use
@@ -368,6 +370,8 @@ help_node=What's this node?
 html_assertion_file=Write JTidy report to file
 html_assertion_label=HTML Assertion
 html_assertion_title=HTML Assertion
+html_extractor_type=CSS/JQuery extractor Implementation
+html_extractor_title=CSS/JQuery extractor
 html_parameter_mask=HTML Parameter Mask
 http_implementation=Implementation:
 http_response_code=HTTP response code

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Sun Dec 16 15:34:56 2012
@@ -113,6 +113,7 @@ assertion_title=Assertion R\u00E9ponse
 assertion_url_samp=URL Echantillon
 assertion_visualizer_title=R\u00E9cepteur d'assertions
 attribute=Attribut \:
+attribute_field=Attribut \:
 attrs=Attributs
 auth_base_url=URL de base
 auth_manager_title=Gestionnaire d'autorisation HTTP
@@ -261,6 +262,7 @@ exit=Quitter
 expand=D\u00E9plier
 expected_return_code_title=Code retour attendu \: 
 expiration=Expiration
+expression_field=Expression CSS/JQuery \:
 field_name=Nom du champ
 file=Fichier
 file_already_in_use=Ce fichier est d\u00E9j\u00E0 utilis\u00E9
@@ -362,6 +364,8 @@ help_node=Quel est ce noeud ?
 html_assertion_file=Ecrire un rapport JTidy dans un fichier
 html_assertion_label=Assertion HTML
 html_assertion_title=Assertion HTML
+html_extractor_title=Extracteur CSS/JQuery
+html_extractor_type=Impl\u00E9mentation de l'extracteur CSS/JQuery
 html_parameter_mask=Masque de param\u00E8tre HTML
 http_implementation=Impl\u00E9mentation \:
 http_response_code=Code de r\u00E9ponse HTTP

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1422599&r1=1422598&r2=1422599&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Sun Dec 16 15:34:56 2012
@@ -192,6 +192,7 @@ to the elements View Results Tree, Asser
 
 <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>
 <ul>
+<li><bugzilla>54259</bugzilla> - Introduce a CSS or jquery-like based Extractor</li>
 </ul>
 
 <h3>Functions</h3>