[英]XPath expression to select unique nodes
I'm working on a project where I have to transform some XML input to some XML output, and for this I'm using XSLT version 1. 我正在开发一个项目,我必须将一些XML输入转换为某些XML输出,为此我使用的是XSLT版本1。
The input XML files I'm working on are huge like 10k+ lines, but I've spent the better part of an hour boiling it down to the following code snippet, which caputures the problem. 我正在处理的输入XML文件非常像10k +行,但我花了大约一小时的时间将其归结为下面的代码片段,它解决了这个问题。
This is the input XML 这是输入XML
<QueryInput >
<Subject>
<Content>
<MunicipalityCode>0217</MunicipalityCode>
</Content>
</Subject>
<QueryResultStep>
<Multistep>
<IterationResponse>
<QueryResult>
<Kommune>0217</Kommune>
</QueryResult>
</IterationResponse>
<IterationResponse>
<QueryResult>
<Kommune>0217</Kommune>
</QueryResult>
</IterationResponse>
<IterationResponse>
<QueryResult>
<Kommune>0223</Kommune>
</QueryResult>
</IterationResponse>
<IterationResponse>
<QueryResult>
<Kommune>0223</Kommune>
</QueryResult>
</IterationResponse>
</Multistep>
</QueryResultStep>
</QueryInput>
The output XML should contain each "Kommune" once, removing duplicates. 输出XML应该包含每个“Kommune”一次,删除重复项。 For this I made the following XSLT code. 为此,我制作了以下XSLT代码。
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xsl xsi xsd">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<QueryResult>
<xsl:variable name="something">
<KommuneCollection>
<xsl:for-each select="QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(.=preceding::*)]">
<NewKommune>
<xsl:value-of select="."/>
</NewKommune>
</xsl:for-each>
</KommuneCollection>
</xsl:variable>
<xsl:copy-of select="$something"/>
</QueryResult>
</xsl:template>
</xsl:transform>
Which produces the following (almost correct) output: 这产生以下(几乎正确)输出:
<KommuneCollection>
<NewKommune>0223</NewKommune>
</KommuneCollection>
But should produce 但应该产生
<KommuneCollection>
<NewKommune>0217</NewKommune>
<NewKommune>0223</NewKommune>
</KommuneCollection>
If I remove the <MunicipalityCode>0217</MunicipalityCode>
in the input XML, all of a sudden it works - but i really dont understand why. 如果我在输入XML中删除<MunicipalityCode>0217</MunicipalityCode>
,它突然起作用 - 但我真的不明白为什么。 Not why it's happening, and I dont know how to address this issue either. 不是为什么会这样,我也不知道如何解决这个问题。 Any help is greatly appreciated! 任何帮助是极大的赞赏!
EDIT: The issue can easily be replicated by copying the input XML into Notepad++, installing the XPathenizer tool, show the window and enter this XPath expression QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(.=preceding::*)]
, and executing the expression. 编辑:通过将输入XML复制到Notepad ++,安装XPathenizer工具,显示窗口并输入此XPath表达式QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(.=preceding::*)]
可以轻松复制该问题QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(.=preceding::*)]
,并执行表达式。 The results can then be seen on teh right side. 然后可以在右侧看到结果。 I suspect the problem to be with the XPath expression used in the for-each
tag in the XSLT. 我怀疑问题与XSLT中for-each
标记中使用的XPath表达式有关。
As michael.hor257k says, Muenchian's grouping will be helpful for you(dealing with large files). 正如michael.hor257k所说,Muenchian的分组对你有帮助(处理大文件)。 But, following will be the correct version of your current try: 但是,以下将是您当前尝试的正确版本:
<xsl:transform version="1.0" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="xsl xsi xsd">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<QueryResult>
<KommuneCollection>
<xsl:for-each select="QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(. = preceding::QueryResult/Kommune )]">
<NewKommune>
<xsl:value-of select="."/>
</NewKommune>
</xsl:for-each>
</KommuneCollection>
</QueryResult>
</xsl:template>
</xsl:transform>
Note : This way is less efficient. 注意 :这种方式效率较低。 You will feel the difference when you use Muenchian's grouping. 当你使用Muenchian的分组时,你会感受到不同。
Your predicate would have worked, but was failing to include "217" because the /QueryInput/Subject/Content/MunicipalityCode
happened to have the value "217". 您的谓词可能有效,但未能包含“217”,因为/QueryInput/Subject/Content/MunicipalityCode
恰好具有值“217”。
If you adjust your predicate filter to match for preceding Kommune
elements instead of any preceding element, then it will produce the desired results: 如果调整谓词过滤器以匹配前面的Kommune
元素而不是任何前面的元素,那么它将产生所需的结果:
[not(.=preceding::Kommune)]
However, it isn't very efficient. 但是,效率不高。 If your file is huge, then using a xsl:key()
and the meunchian method will be more performant. 如果你的文件很大,那么使用xsl:key()
和meunchian方法会更高效 。
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xsl xsi xsd">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="Kommune" match="Kommune" use="."/>
<xsl:template match="/">
<QueryResult>
<xsl:variable name="something">
<KommuneCollection>
<xsl:for-each
select="QueryInput/QueryResultStep/Multistep/
IterationResponse/QueryResult/
Kommune[generate-id(.) =
generate-id(key('Kommune',.)[1])]">
<NewKommune>
<xsl:value-of select="."/>
</NewKommune>
</xsl:for-each>
</KommuneCollection>
</xsl:variable>
<xsl:copy-of select="$something"/>
</QueryResult>
</xsl:template>
</xsl:transform>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.