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

时间:2016-05-05 20:46:22

标签: xslt xslt-2.0

我目前停留在获取一组价值<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>

我想要实现的目标是从DATA和File Tags中获取NAME值,结果如下:

<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部分中的上述代码仅返回以下内容:

<SAMPLE>
   <NAME>DataName1</NAME>
   <NAME>DataName1</NAME>
</SAMPLE>
不幸的是,

取出[(NAME=preceding::NAME)]将返回所有重复的结果..我认为我在正确的位置有过滤器代码,因为我甚至在使用此过滤器之前添加了整体()[]

提前感谢所有帮助/建议!

3 个答案:

答案 0 :(得分:1)

在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>

答案 1 :(得分:0)

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

答案 2 :(得分:0)

<强>予。只需使用(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>

<强> II。 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