Filtering xsl:value-of on attributes
I currently have an XML document like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="./transform.xsl"?>
<Documentation><Tables>
<TABLE TABLE_NAME="FirstTable">
<COLUMN COLUMN_NAME="FirstColumn" ORDINAL_POSITION="1" IS_NULLABLE="NO" DATA_TYPE="int" />
<COLUMN COLUMN_NAME="SecondColumn" ORDINAL_POSITION="2" IS_NULLABLE="NO" DATA_TYPE="int" />
</TABLE>
...
</Tables><Comments>
<COMMENT ForTable="FirstTable" ForColumn="FirstColumn">Description of FirstColumn</COMMENT>
</Comments></Documentation>
My question is, how do I get the value of the COMMENT when looping over the tables and columns? I have:
<xsl:for-each select="//TABLE">
...
<xsl:for-each select="COLUMN">开发者_如何学JAVA;
...
<xsl:value-of select="//COMMENT[@ForTable = @TABLE_NAME and @ForColumn=@COLUMN_NAME]" />
But this doesn't work. Any advice?
It doesn't work because the value-of's select is saying "get the value of all comments whose ForTable attribute has the same value as their TABLE NAME attribute and whose ForColumn attribute has the same value as their COLUMN NAME attribute".
Try something like
<xsl:for-each select="//TABLE">
<xsl:variable name="table_name" select="@TABLE_NAME"/>
...
<xsl:for-each select="COLUMN">
<xsl:variable name="column_name" select="@COLUMN_NAME"/>
...
<xsl:value-of select="//COMMENT[@ForTable=$table_name and @ForColumn=$column_name]" />
Another variant to solve this would be:
<xsl:for-each select="/Documentation/Tables/TABLE">
<!-- select all comments for the current table name… -->
<xsl:variable name="$comments" select="
/Documentation/Comments/COMMENT[@ForTable = current()/@TABLE_NAME]
"/>
<xsl:for-each select="COLUMN">
<!-- …of those, select the one with the current column name -->
<xsl:value-of select="
$comments[@ForColumn = current()/@COLUMN_NAME]
" />
</xsl:for-each>
</xsl:for-each>
The benefits are:
- you only need one variable, instead of two
- the inner for-each can run faster since it is looking at a smaller, pre-filtered data set
Note that:
- I use
current()
to refer to the XSLT context node within XPath predicates. - I avoid
//
in XPath expressions, since it has really bad performance characteristics and should not be used if possible. Your input document structure implies that//
is not necessary.
精彩评论