使用 XSLT 多个键上的不同节点

发布于 2024-09-15 18:26:46 字数 1768 浏览 4 评论 0原文

我想从多个级别的 xml 中获取不同的节点。谁能给我一些提示如何做到这一点?我用谷歌搜索的方法(Muenchian 方法,for-each-group)用单个分组键和简单的层次结构进行了解释。

这是我的 xml 的一个示例:

<persons>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person> 
</persons>

我希望有基于姓名和年龄的不同人员节点,以及一组不同的邮件节点。因此,对于该示例,所需的输出将是:

<persons>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
</persons>

有办法做到这一点吗?预先非常感谢。

i would like to get distinct nodes from my xml on multiple levels. Can anyone please give me some hints how to do this? The methods i googled (Muenchian method, for-each-group) were explained with single grouping keys and plain hierarchy.

Here's an example of my xml:

<persons>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person> 
</persons>

I would like to have distinct person nodes based on name and age, and also a distinct set of mail-nodes. So for the example the desired output would be:

<persons>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
</persons>

Is there a way to do this? Thanks a lot in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

路还长,别太狂 2024-09-22 18:26:46

我。 XSLT 1.0 解决方案

此转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kPersByNameAndAge" match="person"
  use="concat(name, '+', age)"/>

 <xsl:key name="kmailByNameAndAge" match="mail"
  use="concat(../../name, '+', ../../age)"/>

 <xsl:key name="kmailByNameAndAgeAndVal" match="mail"
  use="concat(../../name, '+', ../../age, '+', .)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <persons>
   <xsl:apply-templates select=
   "person[generate-id()
          =
           generate-id(key('kPersByNameAndAge',
                          concat(name, '+', age)
                          )
                           [1]
                      )
           ]
   "/>
  </persons>
 </xsl:template>

 <xsl:template match="mails">
  <mails>
   <xsl:apply-templates select=
    "key('kmailByNameAndAge', concat(../name, '+', ../age))
        [generate-id()
        =
         generate-id(key('kmailByNameAndAgeAndVal',
                         concat(../../name, '+', ../../age, '+', .)
                         )
                          [1]
                     )
         ]
    "/>
  </mails>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时

<persons>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
</persons>

产生所需的正确结果

<persons>
    <person>
        <name>Tom</name>
        <age>20</age>
        <mails>
            <mail>[email protected]</mail>
            <mail>[email protected]</mail>
            <mail>[email protected]</mail>
        </mails>
    </person>
</persons>

二. XSLT 2.0解决方案

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kmailByNameAndAge" match="mail"
  use="concat(../../name, '+', ../../age)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <persons>
   <xsl:for-each-group select="person" group-by="concat(name, '+', age)">
     <xsl:apply-templates select="."/>
   </xsl:for-each-group>
  </persons>
 </xsl:template>

 <xsl:template match="mails">
  <mails>
   <xsl:for-each-group select=
    "key('kmailByNameAndAge', concat(../name, '+', ../age))"
    group-by="concat(../../name, '+', ../../age, '+', .)"
    >
     <xsl:apply-templates select="."/>
   </xsl:for-each-group>
  </mails>
 </xsl:template>
</xsl:stylesheet>

I. XSLT 1.0 solution:

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kPersByNameAndAge" match="person"
  use="concat(name, '+', age)"/>

 <xsl:key name="kmailByNameAndAge" match="mail"
  use="concat(../../name, '+', ../../age)"/>

 <xsl:key name="kmailByNameAndAgeAndVal" match="mail"
  use="concat(../../name, '+', ../../age, '+', .)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <persons>
   <xsl:apply-templates select=
   "person[generate-id()
          =
           generate-id(key('kPersByNameAndAge',
                          concat(name, '+', age)
                          )
                           [1]
                      )
           ]
   "/>
  </persons>
 </xsl:template>

 <xsl:template match="mails">
  <mails>
   <xsl:apply-templates select=
    "key('kmailByNameAndAge', concat(../name, '+', ../age))
        [generate-id()
        =
         generate-id(key('kmailByNameAndAgeAndVal',
                         concat(../../name, '+', ../../age, '+', .)
                         )
                          [1]
                     )
         ]
    "/>
  </mails>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<persons>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
 <person>
  <name>Tom</name>
  <age>20</age>
  <mails>
   <mail>[email protected]</mail>
   <mail>[email protected]</mail>
  </mails>
 </person>
</persons>

produces the wanted, correct result:

<persons>
    <person>
        <name>Tom</name>
        <age>20</age>
        <mails>
            <mail>[email protected]</mail>
            <mail>[email protected]</mail>
            <mail>[email protected]</mail>
        </mails>
    </person>
</persons>

II. XSLT 2.0 solution

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kmailByNameAndAge" match="mail"
  use="concat(../../name, '+', ../../age)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <persons>
   <xsl:for-each-group select="person" group-by="concat(name, '+', age)">
     <xsl:apply-templates select="."/>
   </xsl:for-each-group>
  </persons>
 </xsl:template>

 <xsl:template match="mails">
  <mails>
   <xsl:for-each-group select=
    "key('kmailByNameAndAge', concat(../name, '+', ../age))"
    group-by="concat(../../name, '+', ../../age, '+', .)"
    >
     <xsl:apply-templates select="."/>
   </xsl:for-each-group>
  </mails>
 </xsl:template>
</xsl:stylesheet>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文