1

使用 Jsoup,我在 html 文件中提取 JavaScript 部分。并将其存储为 java String 对象。

我想使用javax.script.ScriptEngine提取 js 函数中的函数列表、变量列表

JavaScript 部分有几个函数部分。

前任)

function a() {
var a_1;
var a_2
...
}

function b() {
    var b_1;
    var b_2;
...
}

function c() {
    var c_1;
    var c_2;
...
}

我的目标就在下面。

列表函数列表

a b c

列表 varListA

a_1 a_2 ...

列表 varListB

b_1 b_2 ...

列表 varListC

c_1 c_2 ...

如何提取函数列表和变量列表(或者可能是值)?

4

3 回答 3

1

我认为您可以在引擎中加载 javascript 后使用 javascript 内省来做到这一点 - 例如对于函数:

ScriptEngine engine;
// create the engine and have it load your javascript
Bindings bind = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Set<String> allAttributes = bind.keySet();
Set<String> allFunctions = new HashSet<String>();
for ( String attr : allAttributes ) {
    if ( "function".equals( engine.eval("typeof " + attr) ) ) {
        allFunctions.add(attr);
    }
}
System.out.println(allFunctions);

我还没有找到一种方法来提取函数内部的变量(局部变量)而不深入研究 javascript 脚本引擎的内部机制(因此使用不安全)。

于 2013-03-21T14:05:24.077 回答
0

这很棘手。ScriptEngineAPI 似乎不适合检查代码。所以,我有这种非常丑陋的解决方案instance ofcast运营商。

       Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
       for (Map.Entry<String, Object> scopeEntry : bindings.entrySet()) {
           Object value = scopeEntry.getValue();
           String name = scopeEntry.getKey();
           if (value instanceof NativeFunction) {
               log.info("Function -> " + name);
               NativeFunction function = NativeFunction.class.cast(value);
               DebuggableScript debuggableFunction = function.getDebuggableView();
               for (int i = 0; i < debuggableFunction.getParamAndVarCount(); i++) {
                   log.info("First level arg: " + debuggableFunction.getParamOrVarName(i));
               }
           } else if (value instanceof Undefined
                   || value instanceof String
                   || value instanceof Number) {
               log.info("Global arg -> " + name);
           }
       }
于 2013-03-21T15:00:17.307 回答
0

我有类似的问题。也许这对其他人会有所帮助。我使用凹槽作为脚本语言。我的任务是从脚本中检索所有可调用的函数。然后按一些标准过滤这个函数。

不幸的是,这种方法仅对 groovy 有用...

获取脚本引擎:

public ScriptEngine getEngine() throws Exception {
    if (engine == null)
        engine = new ScriptEngineManager().getEngineByName(scriptType);
    if (engine == null) 
        throw new Exception("Could not find implementation of " + scriptType);
    return engine;
}  

编译和评估脚本:

public void evaluateScript(String script) throws Exception {
    Bindings bindings = getEngine().getBindings(ScriptContext.ENGINE_SCOPE);
    bindings.putAll(binding);
    try {
        if (engine instanceof Compilable)
            compiledScript = ((Compilable)getEngine()).compile(script);
        getEngine().eval(script);
    } catch (Throwable e) {
        e.printStackTrace();
    } 
}

从脚本中获取函数。除了反射之外,我没有找到其他方法如何从脚本中获取所有可调用方法。是的,我知道这种方法取决于 ScriptEngine 实现,但它是唯一的 :)

public List getInvokableList() throws ScriptException {                
    List list = new ArrayList();
    try {
        Class compiledClass = compiledScript.getClass();
        Field clasz = compiledClass.getDeclaredField("clasz");       
        clasz.setAccessible(true);
        Class scrClass = (Class)clasz.get(compiledScript);
        Method[] methods = scrClass.getDeclaredMethods();            
        clasz.setAccessible(false);
        for (int i = 0, j = methods.length; i < j; i++) {
            Annotation[] annotations = methods[i].getDeclaredAnnotations();
            boolean ok = false;
            for (int k = 0, m = annotations.length; k < m; k++) {
                ok = annotations[k] instanceof CalculatedField;
                if (ok) break;
            }
            if (ok) 
                list.add(methods[i].getName());
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace(); 
    } catch (IllegalAccessException e) {

    }
    return list;
}

在我的任务中,我不需要所有功能,为此我创建自定义注释并在脚本中使用它:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CalculatedField {    
}

Script example:

import com.vssk.CalculatedField;

def utilFunc(s) {     
    s
}

@CalculatedField
def func3() {     
    utilFunc('Testing func from groovy')
}

通过名称调用脚本函数的方法:

public Object executeFunc(String name) throws Exception {
    return ((Invocable)getEngine()).invokeFunction(name);  
}
于 2016-05-05T11:03:12.987 回答