[英]XPath expression to select unique nodes
我正在開發一個項目,我必須將一些XML輸入轉換為某些XML輸出,為此我使用的是XSLT版本1。
我正在處理的輸入XML文件非常像10k +行,但我花了大約一小時的時間將其歸結為下面的代碼片段,它解決了這個問題。
這是輸入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>
輸出XML應該包含每個“Kommune”一次,刪除重復項。 為此,我制作了以下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>
這產生以下(幾乎正確)輸出:
<KommuneCollection>
<NewKommune>0223</NewKommune>
</KommuneCollection>
但應該產生
<KommuneCollection>
<NewKommune>0217</NewKommune>
<NewKommune>0223</NewKommune>
</KommuneCollection>
如果我在輸入XML中刪除<MunicipalityCode>0217</MunicipalityCode>
,它突然起作用 - 但我真的不明白為什么。 不是為什么會這樣,我也不知道如何解決這個問題。 任何幫助是極大的贊賞!
編輯:通過將輸入XML復制到Notepad ++,安裝XPathenizer工具,顯示窗口並輸入此XPath表達式QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(.=preceding::*)]
可以輕松復制該問題QueryInput/QueryResultStep/Multistep/IterationResponse/QueryResult/Kommune[not(.=preceding::*)]
,並執行表達式。 然后可以在右側看到結果。 我懷疑問題與XSLT中for-each
標記中使用的XPath表達式有關。
正如michael.hor257k所說,Muenchian的分組對你有幫助(處理大文件)。 但是,以下將是您當前嘗試的正確版本:
<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>
注意 :這種方式效率較低。 當你使用Muenchian的分組時,你會感受到不同。
您的謂詞可能有效,但未能包含“217”,因為/QueryInput/Subject/Content/MunicipalityCode
恰好具有值“217”。
如果調整謂詞過濾器以匹配前面的Kommune
元素而不是任何前面的元素,那么它將產生所需的結果:
[not(.=preceding::Kommune)]
但是,效率不高。 如果你的文件很大,那么使用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.