使用 XSLT 获取节点 XML 中重复的属性

发布于 2024-12-12 02:14:41 字数 5160 浏览 0 评论 0原文

我尝试获取对象的重复地址,但我不明白为什么我的 foreach 不起作用。我认为这是因为函数generate-id()。

我期望以下结果:

  • 1.1.1.1
  • 主机1
  • 主机2
  • 主机5
  • 主机7

  • 2.2.2.2
  • 主机8
  • 主机9
如果

您能提供帮助,我们将不胜感激。

这是我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

决绝 2024-12-19 02:14:41

您尝试使用的技术称为 Muenchian 分组。您正在尝试按“地址”属性对“主机”属性进行分组。

首先,您已经正确定义了键,但在这种情况下,如果您的 XML 不包含不同命名元素下的 PROPERTY 元素,则可以将其简化为以下内容

<xsl:key name="same-ip" match="PROPERTY[@NAME='address']" use="@VALUE"/>

Muenchian 分组的下一阶段是循环每个组中的第一个元素(在您的情况下,每个“地址”属性的第一个“主机”属性)。这将为您带来独特的群体。

应该这样写:

<xsl:for-each 
  select="db/OBJECT/PROPERTY
    [@NAME='address']
    [generate-id(.)=generate-id(key('same-ip',@VALUE)[1])]">

实际上,在这种情况下,最好使用 xsl:apply-templates,而不是 xsl:for-each

然后,您只需要循环遍历同一组中的所有匹配元素,这可以使用 key 来完成

<xsl:apply-templates select="key('same-ip', @VALUE)">

。这是最终的 XSLT。注意我在这里使用 xsl:apply-templates 而不是 xsl:for-each

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="same-ip" match="PROPERTY[@NAME='address']" use="@VALUE"/>

   <xsl:template match="/">
      <HTML>
         <HEAD>
            <TITLE>Template</TITLE>
         </HEAD>
         <BODY BGCOLOR="#FFFFFF">
            <xsl:apply-templates 
              select="db/OBJECT/PROPERTY
                [@NAME='address']
                [generate-id(.)=generate-id(key('same-ip',@VALUE)[1])]" mode="group"/>
         </BODY>
      </HTML>
   </xsl:template>

   <xsl:template match="PROPERTY[count(key('same-ip', @VALUE)) > 1]" mode="group">
      <ul>
         <li>
            <xsl:value-of select="@VALUE"/>
         </li>
         <xsl:apply-templates select="key('same-ip', @VALUE)"/>
      </ul>
   </xsl:template>

   <xsl:template match="PROPERTY">
      <li>
         <xsl:value-of select="../PROPERTY[@NAME='host']/@VALUE"/>
      </li>
   </xsl:template>
</xsl:stylesheet>

当这应用于给定的 XML 时,以下是输出

<HTML>
   <HEAD>
      <TITLE>Template</TITLE>
   </HEAD>
   <BODY BGCOLOR="#FFFFFF">
      <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>
   </BODY>
</HTML>

请注意以下行,它与我从给定结果中假设的每个组中的第一个元素匹配

<xsl:template match="PROPERTY[count(key('same-ip', @VALUE)) > 1]" mode="group">

,您想要忽略具有一个元素的组(即“地址”属性,只有一个“主机”属性)。如果不是这种情况,只需将其更改为以下内容即可输出所有内容:

<xsl:template match="PROPERTY" mode="group">

另请注意使用 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

<xsl:key name="same-ip" match="PROPERTY[@NAME='address']" use="@VALUE"/>

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:

<xsl:for-each 
  select="db/OBJECT/PROPERTY
    [@NAME='address']
    [generate-id(.)=generate-id(key('same-ip',@VALUE)[1])]">

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

<xsl:apply-templates select="key('same-ip', @VALUE)">

Here is the final XSLT. Note I am using xsl:apply-templates here rather than a xsl:for-each

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="same-ip" match="PROPERTY[@NAME='address']" use="@VALUE"/>

   <xsl:template match="/">
      <HTML>
         <HEAD>
            <TITLE>Template</TITLE>
         </HEAD>
         <BODY BGCOLOR="#FFFFFF">
            <xsl:apply-templates 
              select="db/OBJECT/PROPERTY
                [@NAME='address']
                [generate-id(.)=generate-id(key('same-ip',@VALUE)[1])]" mode="group"/>
         </BODY>
      </HTML>
   </xsl:template>

   <xsl:template match="PROPERTY[count(key('same-ip', @VALUE)) > 1]" mode="group">
      <ul>
         <li>
            <xsl:value-of select="@VALUE"/>
         </li>
         <xsl:apply-templates select="key('same-ip', @VALUE)"/>
      </ul>
   </xsl:template>

   <xsl:template match="PROPERTY">
      <li>
         <xsl:value-of select="../PROPERTY[@NAME='host']/@VALUE"/>
      </li>
   </xsl:template>
</xsl:stylesheet>

When this is applied to your given XML, the following is output

<HTML>
   <HEAD>
      <TITLE>Template</TITLE>
   </HEAD>
   <BODY BGCOLOR="#FFFFFF">
      <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>
   </BODY>
</HTML>

Do note the following line, which matches the first element in each group

<xsl:template match="PROPERTY[count(key('same-ip', @VALUE)) > 1]" mode="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:

<xsl:template match="PROPERTY" mode="group">

Also note the use of the mode attribute to avoid the first template calling itself recursively which would lead to a stack overflow.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文