对元素和属性名称的动态分组 [英] Dynamic grouping on element and attributes names
问题描述
我想将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:choose xsl:when并进行一些测试.我在想(正确的订购完成后):
If element name != previous element name
create headings
Else if all attributes != all previous element's attributes
create headings
我想我最大的问题是,我不知道如何检查以前返回的数据集是什么...有人可以告诉我该怎么做吗?
或者如果我要解决这个错误..请问我有一个更好的解决方案吗?
希望一切都有道理!让我知道您是否需要澄清!
在此先感谢您的耐心等待和回应! :)
此转换不对具有相同数量属性的集合进行任何假设-完全没有假设.
<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/>
I would like to categorize results from an XPath under headings by element name (and then by same attribute names). Note: XML data could be inconsistent and some elements with the same name could have different attributes, therefore they need different headings.
I can't seem to write out my problem in words, so it might be best to use an example..
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']
What the output should sort of look like (with the different headings for different elements):
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
The XSL I currently have (simplified!):
<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>
This above XSL sorts them correctly in the way I want.. but now I need some sort of check to see which elements have the same name, and then if they have the same name, do they have the same attributes. Once I complete this check, I can then put general "Headings" above sets of records with matching element name and attributes.
I figured I could use xsl:choose xsl:when and do some tests. I was thinking (after the correct ordering has been done):
If element name != previous element name
create headings
Else if all attributes != all previous element's attributes
create headings
I guess my biggest problem is, is that I don't know how to check what the previous returned data set was... Can someone please tell me how to do this?
Or if I am approaching this wrong.. lead me to a better solution?
Hope that all made sense! Let me know if you need clarification!
Thanks in advance for your patience and responses! :)
This transformation doesn't make any assumptions about the sets having the same number of attributes -- no assumptions at all.
<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>
When applied on the provided XML document:
<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>
the wanted, correct result is produced:
<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/>
这篇关于对元素和属性名称的动态分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!