我是XML和XLST的新手。我有一个用XML吐出的报告。它有几千条记录,但是一遍又一遍地重复两行数据。我需要一种方法将输出XML文件限制为只有那两个唯一的数据行。
以下是我的XML文件目前的示例:
<zd:Report_Data xmlns:zd="urn:com.xxxx.report/xxxx-Employee_Status-Outbound">
<zd:Report_Entry>
<zd:empStat.emplStatusCode>A</zd:empStat.emplStatusCode>
<zd:empStat.name>Active Employee</zd:empStat.name>
<zd:worker>
<zd:empStat.lastUpdateDate>1/1/1968</zd:empStat.lastUpdateDate>
<zd:empStat.actvInd>1</zd:empStat.actvInd>
</zd:worker>
</zd:Report_Entry>
<zd:Report_Entry>
<zd:empStat.emplStatusCode>A</zd:empStat.emplStatusCode>
<zd:empStat.name>Active Employee</zd:empStat.name>
<zd:worker>
<zd:empStat.lastUpdateDate>1/1/1968</zd:empStat.lastUpdateDate>
<zd:empStat.actvInd>1</zd:empStat.actvInd>
</zd:worker>
</zd:Report_Entry>
<zd:Report_Entry>
<zd:empStat.emplStatusCode>A</zd:empStat.emplStatusCode>
<zd:empStat.name>Active Employee</zd:empStat.name>
<zd:worker>
<zd:empStat.lastUpdateDate>1/1/1968</zd:empStat.lastUpdateDate>
<zd:empStat.actvInd>0</zd:empStat.actvInd>
</zd:worker>
</zd:Report_Entry>
<zd:Report_Entry>
<zd:empStat.emplStatusCode>A</zd:empStat.emplStatusCode>
<zd:empStat.name>Active Employee</zd:empStat.name>
<zd:worker>
<zd:empStat.lastUpdateDate>1/1/1968</zd:empStat.lastUpdateDate>
<zd:empStat.actvInd>0</zd:empStat.actvInd>
</zd:worker>
</zd:Report_Entry>
</zd:Report_Data>
这就是我想要的样子:
<zd:Report_Data xmlns:zd="urn:com.xxxx.report/xxxx-Employee_Status-Outbound">
<zd:Report_Entry>
<zd:empStat.emplStatusCode>A</zd:empStat.emplStatusCode>
<zd:empStat.name>Active Employee</zd:empStat.name>
<zd:worker>
<zd:empStat.lastUpdateDate>1/1/1968</zd:empStat.lastUpdateDate>
<zd:empStat.actvInd>1</zd:empStat.actvInd>
</zd:worker>
</zd:Report_Entry>
<zd:Report_Entry>
<zd:empStat.emplStatusCode>A</zd:empStat.emplStatusCode>
<zd:empStat.name>Active Employee</zd:empStat.name>
<zd:worker>
<zd:empStat.lastUpdateDate>1/1/1968</zd:empStat.lastUpdateDate>
<zd:empStat.actvInd>0</zd:empStat.actvInd>
</zd:worker>
</zd:Report_Entry>
</zd:Report_Data>
^^更新
我看到了一些我认为可以在这个网站上运行的东西(http://stackoverflow.com/questions/3016929/selecting-unique-records-in-xslt-xpath),但我在将它应用到我的情况时遇到了麻烦。任何帮助将不胜感激!
这是我到目前为止基于我在这里读到的另一篇文章。不幸的是,它没有返回任何数据:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kItemBy3Children" match="Report_Entry"
use="concat(empStat.emplStatusCode, '+', empStat.name, '+', empStat.lastUpdateDate, '+', empStat.actvInd)"/>
<xsl:template match="/">
<xsl:copy-of select=
"*/item[generate-id()
= generate-id(key('kItemBy4Children',
concat(empStat.emplStatusCode,
'+', empStat.name,
'+', empStat.lastUpdateDate,
'+', empStat.actvInd)
)
)
]
"/>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
此样式表......
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ZD="urn:com.xxxx.report/xxxx-Employee_Status-Outbound">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kItemBy4Children" match="ZD:Report_Entry"
use="concat(ZD:empStat.emplStatusCode, '+', ZD:empStat.name, '+', ZD:worker/ZD:empStat.lastUpdateDate, '+', ZD:worker/ZD:empStat.actvInd)"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="ZD:Report_Data">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:copy-of select=
"ZD:Report_Entry[ generate-id() = generate-id(key('kItemBy4Children',
concat(ZD:empStat.emplStatusCode, '+', ZD:empStat.name, '+', ZD:worker/ZD:empStat.lastUpdateDate, '+', ZD:worker/ZD:empStat.actvInd))[1])]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
...将转换此输入文档......
<ZD:Report_Data xmlns:ZD="urn:com.xxxx.report/xxxx-Employee_Status-Outbound">
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Terminated Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>0</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Terminated Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>0</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
</ZD:Report_Data>
...进入此输出文档...
<ZD:Report_Data xmlns:ZD="urn:com.xxxx.report/xxxx-Employee_Status-Outbound">
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Terminated Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>0</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
</ZD:Report_Data>
Report_Data节点被分组为具有与4个子成员所测量的内容相同的组。换句话说,每个不同的Report_Data只有一个组,并且只输出每个组的第一个成员。该技术称为Muenchian分组。我可以对Muenchian分组给出一个很长的解释,或者你可以只搜索已经解释过的几百个StackOverflow问题。我只会重复别人写的东西。
搜索的起点:
我修改了empStat.emplStatusCode字段,empStat.name字段应该以ZD开头:worker /
答案 1 :(得分:0)
如果你只需要选择前两行,那就很容易了:
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="*[1]|*[2]"/>
</xsl:copy>
</xsl:template>
但也许我误解了这个问题。
答案 2 :(得分:0)
这是与您的尝试不同的解决方案,因为我没有使用任何密钥。我觉得这样比较容易,因为你不必知道XSLT中的密钥是如何工作的(事实上,我不知道它们是如何工作的,因为到目前为止我从未需要它们。)
请注意,我已为您的命名空间前缀ZD
声明了一些URI;你需要插入你的。
首先,我已经应用了身份模板来基本复制所有内容。
然后,有一个<ZD:Report_Entry>
元素的模板。在该模板中,如果所选元素具有相同内容的前一个兄弟元素,则省略所选元素。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ZD="http://xyz.abc">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/ZD:Report_Data/ZD:Report_Entry">
<xsl:choose>
<xsl:when test="preceding-sibling::ZD:Report_Entry[(ZD:empStat.emplStatusCode = current()/ZD:empStat.emplStatusCode) and (ZD:empStat.name = current()/ZD:empStat.name) and (ZD:worker/ZD:empStat.lastUpdateDate = current()/ZD:worker/ZD:empStat.lastUpdateDate) and (ZD:worker/ZD:empStat.actvInd = current()/ZD:worker/ZD:empStat.actvInd)]"/>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
通过选择前一个兄弟<ZD:Report_Entry>
元素来检查前一个兄弟元素。该元素的条件是其四个内容元素值与所选节点(current()
)的相应内容元素值匹配。
如果您需要根据不同的标准比较相等的记录,请修改方括号中的部分。
测试用例
此示例文档:
<ZD:Report_Data xmlns:ZD="http://xyz.abc">
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Terminated Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>0</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>2</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Terminated Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>0</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
</ZD:Report_Data>
转换为此输出:
<ZD:Report_Data xmlns:ZD="http://xyz.abc">
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>1</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Terminated Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>0</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
<ZD:Report_Entry>
<ZD:empStat.emplStatusCode>A</ZD:empStat.emplStatusCode>
<ZD:empStat.name>Active Employee</ZD:empStat.name>
<ZD:worker>
<ZD:empStat.lastUpdateDate>1/1/1968</ZD:empStat.lastUpdateDate>
<ZD:empStat.actvInd>2</ZD:empStat.actvInd>
</ZD:worker>
</ZD:Report_Entry>
</ZD:Report_Data>
更新: 正确复制了<ZD:Record_Entry>
元素,而不仅仅是其内容。
答案 3 :(得分:0)
我尝试将一些可以实现您想要的东西放在一起,而不是专门针对此XML架构。
我很累,而且很讨厌和hackey(在讨厌之前注意,人们),所以可能有更好的方法,但它似乎有效。
<!-- root and static content -->
<xsl:template match="/">
<root>
<xsl:apply-templates select='*/*' />
</root>
</xsl:template>
<!-- children - output only unique -->
<xsl:template match='*'>
<xsl:variable name='node' select='.' />
<!-- does this node have identical siblings up ahead? If so, skip it, and we'll output a sibling later -->
<xsl:variable name='has_identical_siblings'>
<xsl:for-each select='following-sibling::*[name() = name($node)]'>
<xsl:call-template name='check_identical'>
<xsl:with-param name='this_node_profile'>
<xsl:copy-of select='$node' />
</xsl:with-param>
<xsl:with-param name='check_against'>
<xsl:copy-of select='.' />
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<!-- output? -->
<xsl:if test='not(normalize-space($has_identical_siblings))'>
<xsl:copy-of select='.' />
</xsl:if>
</xsl:template>
<!-- util: two nodes are identical? -->
<xsl:template name='check_identical'>
<xsl:param name='this_node_profile' />
<xsl:param name='check_against' />
<xsl:if test='$this_node_profile = $check_against'>true</xsl:if>
</xsl:template>
You can run it here(参见输出源 - 一名活跃员工,一名终止员工)。