XSLT如何在模板匹配中使用通配符

时间:2017-03-11 08:29:16

标签: xml xslt xpath

我正在尝试在匹配中实现一种通配符机制,以便在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">&quot;prova&quot;</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">&quot;ciao&quot;</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节点。
有人可以帮帮我吗?

2 个答案:

答案 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>