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>
说明:
使用标准 XSLT 2.0 指令 <xsl:for-each-group>
和属性 group-by
。
在 XSLT 1.0 解决方案中使用 Muenchian method for grouping
我目前无法获取一组不同的值,其中值 <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>
说明:
使用标准 XSLT 2.0 指令
<xsl:for-each-group>
和属性group-by
。在 XSLT 1.0 解决方案中使用 Muenchian method for grouping