我想根据元素名称(然后使用相同的属性名称)对标题下的XPath结果进行分类。注意:XML数据可能不一致,一些具有相同名称的元素可能具有不同的属性,因此它们需要不同的标题。
我似乎无法用文字写出我的问题,所以最好使用一个例子..
XML:
<pets>
<dog name="Frank" cute="yes" color"brown" type="Lab"/>
<cat name="Fluffy" cute="yes" color="brown"/>
<cat name="Lucy" cute="no" color="brown"/>
<dog name="Spot" cute="no" color="brown"/>
<dog name="Rover" cute="yes" color="brown"/>
<dog name="Rupert" cute="yes" color="beige" type="Pug"/>
<cat name="Simba" cute="yes" color="grey"/>
<cat name="Princess" color="brown"/>
</pets>
的XPath:
//*[@color='brown']
输出应该是什么样的(具有不同元素的不同标题):
ElementName Color Cute Name Type
Dog Brown Yes Frank Lab
ElementName Color Cute Name
Dog Brown No Spot
Dog Brown Yes Rover
ElementName Color Cute Name
Cat Brown Yes Fluffy
Cat Brown No Lucy
ElementName Color Name
Cat Brown Princess
我目前拥有的XSL(简化!):
<xsl:apply-templates select="//*[@color='brown']" mode="result">
<xsl:sort select="name()" order="ascending"/>
</xsl:apply-templates>
<xsl:template match="@*|node()" mode="result">
<tr>
<th align="left">Element</th>
<xsl:for-each select="@*">
<xsl:sort select="name()" order="ascending"/>
<th align="left">
<xsl:value-of select="name()"/>
</th>
</xsl:for-each>
</tr>
<tr>
<td align="left">
<xsl:value-of select="name()"/>
</td>
<xsl:for-each select="@*">
<xsl:sort select="name()" order="ascending"/>
<td align="left">
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:template>
上面的XSL以我想要的方式对它们进行了正确排序..但现在我需要进行某种检查以查看哪些元素具有相同的名称,然后如果它们具有相同的名称,它们是否具有相同的属性。完成此检查后,我可以将一般“标题”放在具有匹配元素名称和属性的记录集上方。
我想我可以使用xsl:选择xsl:when并做一些测试。我在想(在完成正确的订购之后):
If element name != previous element name
create headings
Else if all attributes != all previous element's attributes
create headings
我想我最大的问题是,我不知道如何检查之前返回的数据集是什么......有人可以告诉我该怎么做吗?
或者,如果我接近这个错误,请引导我找到更好的解决方案?
希望一切都有意义!如果您需要澄清,请告诉我们!
提前感谢您的耐心和回应! :)
答案 0 :(得分:1)
此变换不会对具有相同数量属性的集合做出任何假设 - 根本没有假设。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kAnimalByProperties" match="animal"
use="concat(@atype, .)"/>
<xsl:variable name="vrtfNewDoc">
<xsl:apply-templates select="/pets/*">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:template match="pets/*">
<animal atype="{name()}">
<xsl:copy-of select="@*"/>
<xsl:for-each select="@*">
<xsl:sort select="name()"/>
<attrib>|<xsl:value-of select="name()"/>|</attrib>
</xsl:for-each>
</animal>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="ext:node-set($vrtfNewDoc)">
<xsl:for-each select=
"*[generate-id()
=generate-id(key('kAnimalByProperties',
concat(@atype, .)
)[1]
)
]">
<table border="1">
<tr>
<td>Element Name</td>
<xsl:for-each select="*">
<td><xsl:value-of select="translate(.,'|','')"/></td>
</xsl:for-each>
</tr>
<xsl:for-each select=
"key('kAnimalByProperties', concat(@atype, .))">
<xsl:variable name="vcurAnimal" select="."/>
<tr>
<td><xsl:value-of select="@atype"/></td>
<xsl:for-each select="*">
<td>
<xsl:value-of select=
"$vcurAnimal/@*[name()=translate(current(),'|','')]"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
<p/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<pets>
<dog name="Frank" cute="yes" color="brown" type="Lab"/>
<cat name="Fluffy" cute="yes" color="brown"/>
<cat name="Lucy" cute="no" color="brown"/>
<dog name="Spot" cute="no" color="brown"/>
<dog name="Rover" cute="yes" color="brown"/>
<dog name="Rupert" cute="yes" color="beige" type="Pug"/>
<cat name="Simba" cute="yes" color="grey"/>
<cat name="Princess" color="brown"/>
</pets>
产生了想要的正确结果:
<table border="1">
<tr>
<td>Element Name</td>
<td>color</td>
<td>cute</td>
<td>name</td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>yes</td>
<td>Fluffy</td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>no</td>
<td>Lucy</td>
</tr>
<tr>
<td>cat</td>
<td>grey</td>
<td>yes</td>
<td>Simba</td>
</tr>
</table>
<p/>
<table border="1">
<tr>
<td>Element Name</td>
<td>color</td>
<td>name</td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>Princess</td>
</tr>
</table>
<p/>
<table border="1">
<tr>
<td>Element Name</td>
<td>color</td>
<td>cute</td>
<td>name</td>
<td>type</td>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>yes</td>
<td>Frank</td>
<td>Lab</td>
</tr>
<tr>
<td>dog</td>
<td>beige</td>
<td>yes</td>
<td>Rupert</td>
<td>Pug</td>
</tr>
</table>
<p/>
<table border="1">
<tr>
<td>Element Name</td>
<td>color</td>
<td>cute</td>
<td>name</td>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>no</td>
<td>Spot</td>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>yes</td>
<td>Rover</td>
</tr>
</table>
<p/>
答案 1 :(得分:0)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="ByName-AttNum" match="*/*[@color='brown']" use="concat(name(),'++',count(@*))"/>
<xsl:template match="/">
<html>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="*/*[generate-id(.) = generate-id(key('ByName-AttNum',concat(name(),'++',count(@*)))[1])]">
<table>
<tr>
<th>ElementName</th>
<xsl:apply-templates select="@*" mode="headers">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</tr>
<xsl:apply-templates select="key('ByName-AttNum',concat(name(),'++',count(@*)))" mode="list"/>
</table>
</xsl:template>
<xsl:template match="*" mode="list">
<tr>
<td>
<xsl:value-of select="name()"/>
</td>
<xsl:apply-templates select="@*" mode="list">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="@*" mode="headers">
<th>
<xsl:value-of select="name()"/>
</th>
</xsl:template>
<xsl:template match="@*" mode="list">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
</xsl:stylesheet>
结果:
<html>
<table>
<tr>
<th>ElementName</th>
<th>color</th>
<th>cute</th>
<th>name</th>
<th>type</th>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>yes</td>
<td>Frank</td>
<td>Lab</td>
</tr>
</table>
<table>
<tr>
<th>ElementName</th>
<th>color</th>
<th>cute</th>
<th>name</th>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>yes</td>
<td>Fluffy</td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>no</td>
<td>Lucy</td>
</tr>
</table>
<table>
<tr>
<th>ElementName</th>
<th>color</th>
<th>cute</th>
<th>name</th>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>no</td>
<td>Spot</td>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>yes</td>
<td>Rover</td>
</tr>
</table>
<table>
<tr>
<th>ElementName</th>
<th>color</th>
<th>name</th>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>Princess</td>
</tr>
</table>
</html>
注意:这假设所有具有相同数量属性的元素也具有相同的属性名称(如输入样本中所示)。
编辑:更好的输出标记。
EDIT 2 :另一种解决方案:一个包含所有posible属性的标头(如CSV模式)和按属性计数和名称排序的元素。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="attrByName" match="pets/*/@*" use="name()"/>
<xsl:variable name="attr" select="/pets/*/@*[count(.|key('attrByName',name())[1])=1]"/>
<xsl:template match="pets">
<html>
<table>
<tr>
<th>ElementName</th>
<xsl:apply-templates select="$attr" mode="headers">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</tr>
<xsl:apply-templates select="*[@color='brown']">
<xsl:sort select="count(@*)" order="descending"/>
<xsl:sort select="name()"/>
</xsl:apply-templates>
</table>
</html>
</xsl:template>
<xsl:template match="pets/*">
<tr>
<td>
<xsl:value-of select="name()"/>
</td>
<xsl:apply-templates select="$attr" mode="list">
<xsl:sort select="name()"/>
<xsl:with-param name="node" select="."/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="@*" mode="headers">
<th>
<xsl:value-of select="name()"/>
</th>
</xsl:template>
<xsl:template match="@*" mode="list">
<xsl:param name="node"/>
<td>
<xsl:value-of select="$node/@*[name()=name(current())]"/>
</td>
</xsl:template>
</xsl:stylesheet>
结果:
<html>
<table>
<tr>
<th>ElementName</th>
<th>color</th>
<th>cute</th>
<th>name</th>
<th>type</th>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>yes</td>
<td>Frank</td>
<td>Lab</td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>yes</td>
<td>Fluffy</td>
<td></td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td>no</td>
<td>Lucy</td>
<td></td>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>no</td>
<td>Spot</td>
<td></td>
</tr>
<tr>
<td>dog</td>
<td>brown</td>
<td>yes</td>
<td>Rover</td>
<td></td>
</tr>
<tr>
<td>cat</td>
<td>brown</td>
<td></td>
<td>Princess</td>
<td></td>
</tr>
</table>
</html>
注意:这会在树中运行两次但没有扩展名。没有扩展的所需输出的完全匹配将需要模仿这样的密钥机制:通过树添加新的密钥(元素的名称加上属性的名称)到param,然后再次为每个密钥运行通过树的过滤节点(可能是一个小优化保持非匹配元素的节点集...)。最坏情况(每个带有distinc键的节点)将通过一个节点:N(用于密钥构建)+(N + 1)* N / 2