使用 XSLT 获取节点 XML 中重复的属性
我尝试获取对象的重复地址,但我不明白为什么我的 foreach 不起作用。我认为这是因为函数generate-id()。
我期望以下结果:
如果
您能提供帮助,我们将不胜感激。
这是我的 xls:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Template</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<xsl:apply-templates />
</BODY>
</HTML>
</xsl:template>
<xsl:key name="same-ip" match="db/OBJECT/PROPERTY[@NAME='address']" use="@VALUE" />
<xsl:template match="db/OBJECT">
<xsl:for-each select="//db/OBJECT/PROPERTY[@NAME='address']/@VALUE[generate-id(.)=generate-id(key('same-ip',@VALUE)[1])]">
<ul>
<li><xsl:value-of select='//db/OBJECT/PROPERTY[@NAME="address"]/@VALUE'/> </li>
<li><xsl:value-of select='//db/OBJECT/PROPERTY[@NAME="host"]/@VALUE'/> </li>
</ul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
这是我的 xml:
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet href="trans-simple.xsl" type="text/xsl"?>
<db>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host1" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host2" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host3" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="3.3.3.3" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host4" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="4.4.4.4" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host5" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host7" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host8" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="2.2.2.2" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host9" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="2.2.2.2" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
</db>
I try to get duplicate address for a object but i don't understand why my foreach doesn't work. I think it's because of the function generate-id().
I expect the following result :
<ul>
<li>1.1.1.1</li>
<li>host1</li>
<li>host2</li>
<li>host5</li>
<li>host7</li>
</ul>
<ul>
<li>2.2.2.2</li>
<li>host8</li>
<li>host9</li>
</ul>
Your help would be appreciated
This is my xls :
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Template</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<xsl:apply-templates />
</BODY>
</HTML>
</xsl:template>
<xsl:key name="same-ip" match="db/OBJECT/PROPERTY[@NAME='address']" use="@VALUE" />
<xsl:template match="db/OBJECT">
<xsl:for-each select="//db/OBJECT/PROPERTY[@NAME='address']/@VALUE[generate-id(.)=generate-id(key('same-ip',@VALUE)[1])]">
<ul>
<li><xsl:value-of select='//db/OBJECT/PROPERTY[@NAME="address"]/@VALUE'/> </li>
<li><xsl:value-of select='//db/OBJECT/PROPERTY[@NAME="host"]/@VALUE'/> </li>
</ul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This is my xml :
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet href="trans-simple.xsl" type="text/xsl"?>
<db>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host1" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host2" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host3" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="3.3.3.3" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host4" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="4.4.4.4" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host5" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host7" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="1.1.1.1" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host8" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="2.2.2.2" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
<OBJECT>
<PROPERTY NAME="__type"
VALUE=".com.enterprise.dns.host_address" />
<PROPERTY NAME="rrset_order_position" VALUE="0" />
<PROPERTY NAME="host"
VALUE="host9" />
<PROPERTY NAME="is_ipv4" VALUE="true" />
<PROPERTY NAME="address" VALUE="2.2.2.2" />
<PROPERTY NAME="v6_prefix" VALUE="" />
<PROPERTY NAME="configure_for_dhcp" VALUE="false" />
</OBJECT>
</db>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您尝试使用的技术称为 Muenchian 分组。您正在尝试按“地址”属性对“主机”属性进行分组。
首先,您已经正确定义了键,但在这种情况下,如果您的 XML 不包含不同命名元素下的 PROPERTY 元素,则可以将其简化为以下内容
Muenchian 分组的下一阶段是循环每个组中的第一个元素(在您的情况下,每个“地址”属性的第一个“主机”属性)。这将为您带来独特的群体。
应该这样写:
实际上,在这种情况下,最好使用 xsl:apply-templates,而不是 xsl:for-each
然后,您只需要循环遍历同一组中的所有匹配元素,这可以使用 key 来完成
。这是最终的 XSLT。注意我在这里使用 xsl:apply-templates 而不是 xsl:for-each
当这应用于给定的 XML 时,以下是输出
请注意以下行,它与我从给定结果中假设的每个组中的第一个元素匹配
,您想要忽略具有一个元素的组(即“地址”属性,只有一个“主机”属性)。如果不是这种情况,只需将其更改为以下内容即可输出所有内容:
另请注意使用 mode 属性以避免第一个模板递归调用自身,从而导致堆栈溢出。
The technique you are trying to use is called Muenchian grouping. You are trying to group your 'host' properties, by the 'address' property.
Firstly, you have defined the key correctly, although in this case it could be simplified to the following if your XML didn't contain PROPERTY elements under differently named elements
The next stage in Muenchian grouping is to loop through the first element in each group (In your case, the first 'host' propertry for each 'address' property). This will get you your distinct groups.
This is how it should be written:
Actually, it is better practise to use xsl:apply-templates in this case, rather than a xsl:for-each
Then, you just need to loop through all the matching elements in the same group, which can be done be using the key
Here is the final XSLT. Note I am using xsl:apply-templates here rather than a xsl:for-each
When this is applied to your given XML, the following is output
Do note the following line, which matches the first element in each group
I had assumed from your given result, you wanted to ignore groups with one element (i.e. 'Address' Properties, with only one 'host' property). If this is not the case, simply change it to the following to output everything:
Also note the use of the mode attribute to avoid the first template calling itself recursively which would lead to a stack overflow.