XSLT 从多个元素级别返回不同的数据集

XSLT Returning Distinct Sets of Data from multiple Element Level

我目前无法获取一组不同的值,其中值 <NAME> 是关键。 我有以下示例 XML:

<SAMPLE>
    <FIRST>
        <SUBSET>
            <DATA>
                <NAME>DataName1</NAME>
            </DATA>
            <FILE>
                <NAME>DataName5</NAME>
            </FILE>         
        </SUBSET>
    </FIRST>
    <SECOND>
        <DATA>
            <NAME>DataName1</NAME>
        </DATA> 
        <FILE>
            <NAME>DataName2</NAME>
        </FILE> 
        <DATA>
            <NAME>DataName3</NAME>
        </DATA>         
    </SECOND>
    <THIRD>
        <DATA>
            <NAME>DataName1</NAME>
        </DATA>
        <FILE>
            <NAME>DataName4</NAME>
        </FILE>         
    </THIRD>
</SAMPLE>

我想要实现的是从数据和文件标签中获取名称值,结果如下:

<SAMPLE>
   <NAME>DataName1</NAME>
   <NAME>DataName2</NAME>
   <NAME>DataName3</NAME>
   <NAME>DataName4</NAME>
   <NAME>DataName5</NAME>
</SAMPLE>

下面是我使用 [(NAME=preceding::NAME)] 的代码,但它不起作用..

<xsl:template name="Sample">
    <SAMPLE>    
        <xsl:for-each select="((($srcFile/SAMPLE/FIRST/SUBSET)|($srcFile/SAMPLE/SECOND)|($srcFile/SAMPLE/THIRD))/(DATA | FILE))[(NAME=preceding::NAME)]">
                <xsl:for-each select="NAME"><xsl:element name="{name(.)}"><xsl:value-of select="."/></xsl:element></xsl:for-each>                    
        </xsl:for-each>
    </SAMPLE>
</xsl:template>    

<xsl:template match="/">
    <xsl:call-template name="Sample"/>                 
</xsl:template>

for-each 部分中的上述代码,不幸的是,仅 return编辑了以下内容:

<SAMPLE>
   <NAME>DataName1</NAME>
   <NAME>DataName1</NAME>
</SAMPLE>

不幸的是,取出 [(NAME=preceding::NAME)] 会 return 所有重复的结果。我认为我的过滤器代码在正确的位置,因为我什至在使用它之前添加了整体 ()过滤器[]

提前感谢所有 help/suggestions!

在 XSLT 2.0 中,这是相当微不足道的:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/">
    <SAMPLE>
        <xsl:for-each select="distinct-values(//NAME)">
            <NAME>
                <xsl:value-of select="." />
            </NAME>
        </xsl:for-each>
    </SAMPLE>
</xsl:template>

</xsl:stylesheet>

一个简单的 XSLT-1.0 解决方案是排除重复项并按词法顺序对它们进行排序。生成所有 NAME 个节点的 xsl:key 并将此列表再次与所有 NAME 个节点进行比较:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" />
  <xsl:key name="names" match="NAME" use="text()" />

  <xsl:template match="/SAMPLE">
    <SAMPLE>
      <xsl:for-each select="//NAME[generate-id() = generate-id(key('names',text()))]">
        <xsl:sort select="." order="ascending" />
        <NAME><xsl:value-of select="." /></NAME>
      </xsl:for-each>
    </SAMPLE>
  </xsl:template>

</xsl:stylesheet>

输出为:

<?xml version="1.0"?>
<SAMPLE>
    <NAME>DataName1</NAME>
    <NAME>DataName2</NAME>
    <NAME>DataName3</NAME>
    <NAME>DataName4</NAME>
    <NAME>DataName5</NAME>
</SAMPLE>

我。只需使用 (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:variable name="vDoc" select="document('file:///C:/temp/delete/sample.xml')"/>

  <xsl:template match="/*">
    <xsl:for-each-group select="$vDoc/*/SECOND/SET" group-by="NAME">
      <xsl:sequence select="."/>
    </xsl:for-each-group>
  </xsl:template>
</xsl:stylesheet>

当此转换应用于任何源 XML 文档 (未使用)和文件 C:\temp\delete\sample.xml(注意我已更改值SAMPLE\FIRST\SET\NAME表示没有复制到结果树):

<SAMPLE>
    <FIRST>
        <SET>
            <NAME>manX</NAME>
            <STRING1>what</STRING1>
            <STRING2>today</STRING2>
        </SET>
    </FIRST>
    <SECOND>
        <SET>
            <NAME>man1</NAME>
            <STRING1>what</STRING1>
            <STRING2>today</STRING2>
        </SET>
        <SET>
            <NAME>man1</NAME>
            <STRING1>what</STRING1>
            <STRING2>today</STRING2>
        </SET>
        <SET>
            <NAME>man2</NAME>
            <STRING1>how</STRING1>
            <STRING2>tomorrow</STRING2>
        </SET>
        <SET>
            <NAME>man3</NAME>
            <STRING1>hello</STRING1>
            <STRING2>yesterday</STRING2>
        </SET>
    </SECOND>
</SAMPLE>

产生了想要的、正确的结果:

<SET>
   <NAME>man1</NAME>
   <STRING1>what</STRING1>
   <STRING2>today</STRING2>
</SET>
<SET>
   <NAME>man2</NAME>
   <STRING1>how</STRING1>
   <STRING2>tomorrow</STRING2>
</SET>
<SET>
   <NAME>man3</NAME>
   <STRING1>hello</STRING1>
   <STRING2>yesterday</STRING2>
</SET>

二. 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:variable name="vDoc" select="document('file:///C:/temp/delete/sample.xml')"/>

 <xsl:key name="kSecondSetsByName" match="SECOND/SET" use="NAME"/>

  <xsl:template match="/">
     <xsl:apply-templates select="$vDoc/*/SECOND"/>
  </xsl:template>

  <xsl:template match="SET[generate-id()=generate-id(key('kSecondSetsByName', NAME)[1])]">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>

说明:

  1. 使用标准 XSLT 2.0 指令 <xsl:for-each-group> 和属性 group-by

  2. 在 XSLT 1.0 解决方案中使用 Muenchian method for grouping