Reputation: 343
My XML code is,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<unit
xmlns="http://www.srcML.org/srcML/src" revision="0.9.5" language="Java" filename="ListSample.java">
<class>
<specifier>public</specifier> class
<name>ListSample</name>
<block>{
<decl_stmt>
<decl>
<specifier>private</specifier>
<type>
<name>List</name>
</type>
<name>nameList</name>
<init>=
<expr>
<operator>new</operator>
<call>
<name>List</name>
<argument_list>()</argument_list>
</call>
</expr>
</init>
</decl>;
</decl_stmt>
<function>
<specifier>public</specifier>
<type>
<name>void</name>
</type>
<name>method</name>
<parameter_list>()</parameter_list>
<block>{
<expr_stmt>
<expr>
<call>
<name>
<name>nameList</name>
<operator>.</operator>
<name>add</name>
</name>
<argument_list>(
<argument>
<expr>
<literal type="string">"name"</literal>
</expr>
</argument>)
</argument_list>
</call>
</expr>;
</expr_stmt>
}
</block>
</function>
}
</block>
</class>
I am trying to extract the data type of any List. For example, nameList is a list given in the XML file. I am trying to achieve this by searching the name of the list (preceded by the List keyword) and then by determining the data type from literal type="string". Here, is my code using XPath and XSLT.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template
match="//*[local-name()='name'][preceding-sibling::node()='List']">
<xsl:variable name="listName" select="text()"></xsl:variable>
<xsl:call-template name="getType">
<xsl:with-param name="listName" select="$listName" />
</xsl:call-template>
</xsl:template>
<xsl:template name="getType"
match="//*[local-name()='name'][following-sibling::node()='.' and following-sibling::node()[2]='add']">
<xsl:param name="listName" />
<xsl:if test="node()=$listName">
<xsl:message>
<xsl:value-of select="parent::node()/following-sibling::literal/@type" />
</xsl:message>
</xsl:if>
</xsl:template>
However, the part enclosed in the message
<xsl:message>
<xsl:value-of select="parent::node()/following-sibling::literal/@type" />
</xsl:message>
is unable to get the literal type. How can I correct the code so that I can get the literal node and the data type in the attribute? Thanks in advance.
Upvotes: 2
Views: 2148
Reputation: 101682
I'm still not sure what the purpose of this is, but this produces the expected result:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:src="http://www.srcML.org/srcML/src"
>
<!-- key to locate the usage of a list in an .add() operation based on the list
variable's name -->
<xsl:key name="kListUsage"
match="src:call[src:name[src:operator[1] = '.' and src:name[2] = 'add']]"
use="src:name/src:name[1]" />
<!-- Override default handling of text nodes -->
<xsl:template match="text()" />
<xsl:template match="src:decl[src:type/src:name = 'List']/src:name">
<xsl:apply-templates select="key('kListUsage', .)[1]" mode="listUsage" />
</xsl:template>
<xsl:template match="src:call" mode="listUsage">
<xsl:message>
<xsl:value-of select="src:argument_list/src:argument[1]/src:expr/src:literal/@type"/>
</xsl:message>
</xsl:template>
</xsl:stylesheet>
When run on your sample input, this outputs the following message:
string
Among other things, it seems you're focusing too much nodes' positions relative to each other when the logic will be cleaner if you think about where they are respective to their shared ancestors and work down from those shared ancestors.
Upvotes: 4
Reputation: 66724
Given your current XPath, there are several adjustments that would need to be made:
/unit/class/block/decl_stmt/decl/type/name
element, you need to jump up two levels. The parent is type
and you want to go up to the decl
elementdecl
element, the following-sibling is the function
element, which will have the literal
descendantliteral
element as if was bound to the "no namespace", so adjust to select by local-name()
as you have done in other areasAn updated XPath that produces "string" in the message:
parent::*/parent::node()/following-sibling::*//*[local-name()='literal']/@type"
You could also write it like this:
../../following-sibling::*//*[local-name()='literal']/@type
You might be able to just use the following::
axis and write more succinctly:
../../following::*[local-name()='literal']/@type
Upvotes: 1