我正在尝试在匹配中实现一种通配符机制,以便在XSLT模板中使用。
我最初的问题是我在一组文件中寻找java代码行。我正在寻找的线路可能是这样的:
a.setValue(2);
System.out.println(a.toString());
a.getValue();
在这一行中,a
不是确切的变量名,而是一种占位符。我正在寻找三个java代码行,其中以这种方式使用相同的变量。
为了实现我的目标,我想到了使用XSLT,因为有了它我想解释这种概念。
使用srcml我在xml中翻译了java代码,这是我需要查找java代码行的xml表。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<unit filename="Users/bibi/Documents/UniMi/CloudStation/TesiM/DSL/DSL/resources/src/src_beautified/strategy/StrategyExample.java" language="Java" revision="0.9.5" xmlns="http://www.srcML.org/srcML/src">
<package>package
<name>strategy</name>
;</package>
<import>import
<name>
<name>strategy</name>
<operator>.</operator>
<name>strategy</name>
<operator>.</operator>
<name>HelloWorld</name></name>;</import>
<import>import
<name>
<name>strategy</name>
<operator>.</operator>
<name>strategy</name>
<operator>.</operator>
<name>SubArray</name></name>;</import>
<class>
<specifier>public</specifier>class
<name>StrategyExample</name>
<block>
{
<function>
<specifier>public</specifier>
<specifier>static</specifier>
<type>
<name>void</name></type>
<name>main</name>
<parameter_list>(
<parameter>
<decl>
<type>
<name>
<name>String</name>
<index>[]</index></name>
</type>
<name>args</name>
</decl>
</parameter>)</parameter_list>
<block>{
<decl_stmt>
<decl>
<type>
<name>MyArray</name></type>
<name>m</name>
<init>=
<expr>
<operator>new</operator>
<call>
<name>MyArray</name>
<argument_list>
(
<argument>
<expr>
<literal type="number">10</literal></expr>
</argument>)</argument_list>
</call>
</expr>
</init>
</decl>;</decl_stmt>
<decl_stmt>
<decl>
<type>
<name>HelloWorld</name>
</type>
<name>hw</name>
<init>=
<expr>
<operator>new</operator>
<call>
<name>HelloWorld</name>
<argument_list>()</argument_list></call>
</expr>
</init>
</decl>;</decl_stmt>
<expr_stmt>
<expr>
<call>
<name>
<name>System</name>
<operator>.</operator>
<name>out</name>
<operator>.</operator>
<name>println</name>
</name>
<argument_list>(
<argument>
<expr>
<call>
<name>
<name>hw</name>
<operator>.</operator>
<name>getString</name></name>
<argument_list>(
<argument>
<expr>
<literal type="string">"prova"</literal></expr>
</argument>)</argument_list>
</call>
<operator>.</operator>
<call>
<name>substring</name>
<argument_list>(
<argument>
<expr>
<literal type="number">0</literal></expr>
</argument>,
<argument>
<expr>
<literal type="number">3</literal></expr>
</argument>)</argument_list>
</call>
</expr>
</argument>)</argument_list>
</call>
</expr>;</expr_stmt>
<expr_stmt>
<expr>
<call>
<name>
<name>m</name>
<operator>.</operator>
<name>setValue</name>
</name>
<argument_list>(
<argument>
<expr>
<literal type="number">1</literal></expr>
</argument>,
<argument>
<expr>
<literal type="number">6</literal></expr>
</argument>)</argument_list>
</call>
</expr>;</expr_stmt>
<expr_stmt>
<expr>
<call>
<name>
<name>m</name>
<operator>.</operator>
<name>setValue</name>
</name>
<argument_list>(
<argument>
<expr>
<literal type="number">0</literal></expr>
</argument>,
<argument>
<expr>
<literal type="number">8</literal></expr>
</argument>)</argument_list>
</call>
</expr>;</expr_stmt>
<expr_stmt>
<expr>
<call>
<name>
<name>hw</name>
<operator>.</operator>
<name>getString</name>
</name>
<argument_list>(
<argument>
<expr>
<operator>new</operator>
<call>
<name>String</name>
<argument_list>
(
<argument>
<expr>
<literal type="string">"ciao"</literal></expr>
</argument>)</argument_list>
</call>
</expr>
</argument>)</argument_list>
</call>
</expr>;</expr_stmt>
}</block>
</function>}</block>
</class>
在这个例子中,我想寻找这两行:
m.setValue( 1 , 6 );
m.setValue( 0 , 8 );
为了捕获这一行,我在xslt模板中使用的xpath匹配是这样的:
src:expr_stmt
[src:expr[src:call[src:name[src:operator='.'][src:name='setValue']]
[src:argument_list
[src:argument[src:expr[src:literal='1'][src:literal[contains(@type, 'number')]]]]
[src:argument[src:expr[src:literal='6'][src:literal[contains(@type, 'number')]]]]]]]
[following-sibling::*[2][self::src:expr_stmt
[src:expr[src:call[src:name[src:name[matches(@name, preceding-sibling::*[2]/@src_expr/src_call/src_name/src:name)]
[src:operator='.'][src:name='setValue']]
[src:argument_list[src:argument[src:expr[src:literal='0'][src:literal[contains(@type, 'number')]]]]
[src:argument[src:expr[src:literal='8'][src:literal[contains(@type, 'number')]]]]]]]]]]
但它不起作用,因为它选择了所有src:expr_stmt
节点。
有人可以帮帮我吗?
答案 0 :(得分:2)
我不确定我是否已经理解了这个问题,我认为如果你发布了一个简化的输入样本会更好但是因为我无法真正尝试将问题讨论成评论我将这个分组建议作为讨论发布贡献:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
xpath-default-namespace="http://www.srcML.org/srcML/src"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:for-each-group select="//expr_stmt[expr/call/name[name]]" group-by="expr/call/name/name">
<variable name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<statement>
<xsl:value-of select="normalize-space()"/>
</statement>
</xsl:for-each>
</variable>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
当我针对已发布的输入样本运行此操作并添加了一些结束标记时,我得到了
<variable name="m">
<statement>m . printString ( @ CallBehavior ( id = "mf-getFormatType-0" , behavior = "MathFormat.getFormatType.String[]" ) { @ CallAction ( id = "main-mf.getFormatType-callActionExpr0" ) { mf . getFormatType () }}) ;</statement>
<statement>m . printString ( @ CallBehavior ( id = "m-printString-2" , behavior = "MyArray.printString.String[String-]" ) { @ CallAction ( id = "main-m.printString-callActionExpr1" ) { m . printString ( "ciao" ) }}) . length () ;</statement>
<statement>m . setValue ( 1 , 6 ) ;</statement>
<statement>m . setValue ( 0 , 8 ) ;</statement>
<statement>m . setValue ( 4 , 1 ) ;</statement>
<statement>m . setValue ( 9 , 7 ) ;</statement>
<statement>m . getValue ( j ) ;</statement>
<statement>m . setValue ( j , j + 1 ) ;</statement>
</variable>
<variable name="printString">
<statement>m . printString ( @ CallBehavior ( id = "mf-getFormatType-0" , behavior = "MathFormat.getFormatType.String[]" ) { @ CallAction ( id = "main-mf.getFormatType-callActionExpr0" ) { mf . getFormatType () }}) ;</statement>
<statement>m . printString ( @ CallBehavior ( id = "m-printString-2" , behavior = "MyArray.printString.String[String-]" ) { @ CallAction ( id = "main-m.printString-callActionExpr1" ) { m . printString ( "ciao" ) }}) . length () ;</statement>
</variable>
<variable name="MyArray">
<statement>MyArray . printValue () ;</statement>
</variable>
<variable name="printValue">
<statement>MyArray . printValue () ;</statement>
</variable>
<variable name="setValue">
<statement>m . setValue ( 1 , 6 ) ;</statement>
<statement>m . setValue ( 0 , 8 ) ;</statement>
<statement>m . setValue ( 4 , 1 ) ;</statement>
<statement>m . setValue ( 9 , 7 ) ;</statement>
<statement>m . setValue ( j , j + 1 ) ;</statement>
</variable>
<variable name="getValue">
<statement>m . getValue ( j ) ;</statement>
</variable>
这至少看起来是解决问题的一步吗?可能是那些了解复杂输入格式的人可以进一步调整XPath或分组,但也许该建议显示了如何以格式提取和分组某些元素。
例如
<xsl:template match="/">
<xsl:for-each-group select="//expr_stmt[expr/call/name[name]]" group-by="expr/call/name/name[1]">
<variable name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<statement>
<xsl:value-of select="normalize-space()"/>
</statement>
</xsl:for-each>
</variable>
</xsl:for-each-group>
</xsl:template>
我们只得到
<variable name="m">
<statement>m . printString ( @ CallBehavior ( id = "mf-getFormatType-0" , behavior = "MathFormat.getFormatType.String[]" ) { @ CallAction ( id = "main-mf.getFormatType-callActionExpr0" ) { mf . getFormatType () }}) ;</statement>
<statement>m . printString ( @ CallBehavior ( id = "m-printString-2" , behavior = "MyArray.printString.String[String-]" ) { @ CallAction ( id = "main-m.printString-callActionExpr1" ) { m . printString ( "ciao" ) }}) . length () ;</statement>
<statement>m . setValue ( 1 , 6 ) ;</statement>
<statement>m . setValue ( 0 , 8 ) ;</statement>
<statement>m . setValue ( 4 , 1 ) ;</statement>
<statement>m . setValue ( 9 , 7 ) ;</statement>
<statement>m . getValue ( j ) ;</statement>
<statement>m . setValue ( j , j + 1 ) ;</statement>
</variable>
<variable name="MyArray">
<statement>MyArray . printValue () ;</statement>
</variable>
或者
<xsl:template match="/">
<xsl:for-each-group select="//expr_stmt
[expr[call[name[operator='.'][name='setValue']]
[argument_list
[argument[expr[literal= (1, 0)][literal[contains(@type, 'number')]]]]
[argument[expr[literal= (6, 8)][literal[contains(@type, 'number')]]]]]]]" group-by="expr/call/name/name[1]">
<variable name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<statement>
<xsl:value-of select="normalize-space()"/>
</statement>
</xsl:for-each>
</variable>
</xsl:for-each-group>
</xsl:template>
会给出
<variable name="m">
<statement>m . setValue ( 1 , 6 ) ;</statement>
<statement>m . setValue ( 0 , 8 ) ;</statement>
</variable>
答案 1 :(得分:1)
如果我现在正确理解你的要求,我认为按键有助于解决这个问题。这是您提供的后一个示例的XSLT(使用两个.setValue
):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:src="http://www.srcML.org/srcML/src">
<xsl:output method="xml" indent="yes"/>
<!-- key for first statement pattern -->
<xsl:key name="expr1"
match="src:expr_stmt[src:expr/src:call[
src:name[src:operator = '.' and src:name[2] = 'setValue']
and
src:argument_list[
src:argument[1]/src:expr/src:literal = 1 and
src:argument[2]/src:expr/src:literal = 6
]
]]"
use="src:expr/src:call/src:name/src:name[1]"
/>
<!-- key for second statement pattern -->
<xsl:key name="expr2"
match="src:expr_stmt[src:expr/src:call[
src:name[src:operator = '.' and src:name[2] = 'setValue']
and
src:argument_list[
src:argument[1]/src:expr/src:literal = 0 and
src:argument[2]/src:expr/src:literal = 8
]
]]"
use="src:expr/src:call/src:name/src:name[1]"
/>
<xsl:template match="text()" />
<xsl:template match="/">
<n>
<xsl:apply-templates/>
</n>
</xsl:template>
<!-- breakdown of this expression:
count(key('N', path)) = count(. | key('N', path)) -> the current node is in key N
(the current node is in key expr1 OR
the current node is in key expr2)
AND
there is a node in key expr1 for the current node's first src:name
AND
there is a node in key expr2 for the current node's first src:name
-->
<xsl:template match="src:expr_stmt[(count(key('expr1', src:expr/src:call/src:name/src:name[1])) =
count(. | key('expr1', src:expr/src:call/src:name/src:name[1])) or
count(key('expr2', src:expr/src:call/src:name/src:name[1])) =
count(. | key('expr2', src:expr/src:call/src:name/src:name[1])))
and
key('expr1', src:expr/src:call/src:name/src:name[1])
and
key('expr2', src:expr/src:call/src:name/src:name[1])]">
<xsl:copy-of select="." />
</xsl:template>
</xsl:stylesheet>
在示例XML上运行时,输出为:
<?xml version="1.0" encoding="utf-8"?>
<n xmlns:src="http://www.srcML.org/srcML/src">
<expr_stmt xmlns="http://www.srcML.org/srcML/src">
<expr>
<call>
<name>
<name>m</name>
<operator>.</operator>
<name>setValue</name>
</name>
<argument_list>
(
<argument>
<expr>
<literal type="number">1</literal>
</expr>
</argument>,
<argument>
<expr>
<literal type="number">6</literal>
</expr>
</argument>)
</argument_list>
</call>
</expr>;
</expr_stmt>
<expr_stmt xmlns="http://www.srcML.org/srcML/src">
<expr>
<call>
<name>
<name>m</name>
<operator>.</operator>
<name>setValue</name>
</name>
<argument_list>
(
<argument>
<expr>
<literal type="number">0</literal>
</expr>
</argument>,
<argument>
<expr>
<literal type="number">8</literal>
</expr>
</argument>)
</argument_list>
</call>
</expr>;
</expr_stmt>
</n>