我想知道在最终再次转换之前如何合并2个XML流。
这两个流是
输入1
<Response>
<Instrument>
<Date value="2010-09-02">
<Quantity>10</Quantity>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument TICKER="APPL" />
<SF></SF>
<Instrument>
<Date value="2010-09-02">
<Quantity>20</Quantity>
</Date>
<DXLID>2</DXLID>
</Instrument>
<Instrument TICKER="APPL" />
<SF></SF>
</Response>
输入2
<Response>
<IM>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>3</DXLID>
</Instrument>
</IM>
</Response>
所需输出
<Response>
<All>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
<Quantity>10</Quantity>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<Quantity>20</Quantity>
</Date>
<DXLID>2</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>3</DXLID>
</Instrument>
</All>
</Response>
合并需要基于DXLID
节点值与value
节点的Date
属性之间的匹配。
另请注意,合并需要双向合并。
答案 0 :(得分:2)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kInstrumentByDateAndDXLID" match="Instrument"
use="concat(Date/@value,'++',DXLID)"/>
<xsl:variable name="vSource1"
select="document('Doc1.xml')/Response/Instrument[Date][DXLID]"/>
<xsl:variable name="vSource2"
select="document('Doc2.xml')/Response/IM/Instrument"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<Response>
<All>
<xsl:apply-templates select="$vSource1|$vSource2">
<xsl:sort select="DXLID"/>
</xsl:apply-templates>
</All>
</Response>
</xsl:template>
<xsl:template match="Date/*[last()]">
<xsl:call-template name="identity"/>
<xsl:if test="count(../..|$vSource1)=count($vSource1)">
<xsl:variable name="vKey"
select="concat(../@value,'++',../../DXLID)"/>
<xsl:for-each select="$vSource2[last()]">
<xsl:apply-templates
select="key('kInstrumentByDateAndDXLID',$vKey)/Date/*"/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="Instrument">
<xsl:if test="count(.|$vSource1)=count($vSource1) or
not($vSource1[key('kInstrumentByDateAndDXLID',
concat(current()/Date/@value,'++',
current()/DXLID))])">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输出:
<Response>
<All>
<Instrument>
<Date value="2010-09-02">
<Quantity>10</Quantity>
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<Quantity>20</Quantity>
</Date>
<DXLID>2</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>3</DXLID>
</Instrument>
</All>
</Response>
注意:使用apply-templates可以立即运行合并和第二步转换。此外,将fn:document
用于多个输入源,并将XPath测试用于包含:count($node|$node-set)=count($node-set)
修改:与键相同。看起来MSXSL4有一个错误,这就是为什么我正在使用$vSource2[last()]
代替$vSource2[1]
答案 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:key name="kDateByValAndId" match="Date"
use="concat(@value, '+', ../DXLID)"/>
<xsl:variable name="vDoc1" select="/"/>
<xsl:variable name="vrtfDoc2">
<Response>
<IM>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>3</DXLID>
</Instrument>
</IM>
</Response>
</xsl:variable>
<xsl:variable name="vDoc2" select=
"document('')/*/xsl:variable[@name='vrtfDoc2']"/>
<xsl:template match="/">
<Response>
<All>
<xsl:apply-templates select="/*/node()"/>
<xsl:apply-templates mode="doc2" select=
"$vDoc2/*/*/Instrument[Date and DXLID]" />
</All>
</Response>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Date">
<xsl:variable name="vkeyVal" select=
"concat(@value, '+', ../DXLID)"/>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:for-each select="$vDoc2">
<xsl:apply-templates select="key('kDateByValAndId', $vkeyVal)/node()"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="SF|Instrument[@TICKER='APPL']"/>
<xsl:template match="Instrument" mode="doc2">
<xsl:variable name="vkeyVal" select=
"concat(Date/@value, '+', DXLID)"/>
<xsl:variable name="vcur" select="."/>
<xsl:for-each select="$vDoc1">
<xsl:if test="not(key('kDateByValAndId', $vkeyVal))">
<xsl:copy-of select="$vcur"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
应用于原始第一份文件:
<Response>
<Instrument>
<Date value="2010-09-02">
<Quantity>10</Quantity>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument TICKER="APPL" />
<SF></SF>
<Instrument>
<Date value="2010-09-02">
<Quantity>20</Quantity>
</Date>
<DXLID>2</DXLID>
</Instrument>
<Instrument TICKER="APPL" />
<SF></SF>
</Response>
生成想要的正确结果:
<Response>
<All>
<Instrument>
<Date value="2010-09-02">
<Quantity>10</Quantity>
<SAF xmlns:xsl="http://www.w3.org/1999/XSL/Transform">1</SAF>
<SAR xmlns:xsl="http://www.w3.org/1999/XSL/Transform">2</SAR>
</Date>
<DXLID>1</DXLID>
</Instrument>
<Instrument>
<Date value="2010-09-02">
<Quantity>20</Quantity>
</Date>
<DXLID>2</DXLID>
</Instrument>
<Instrument xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<Date value="2010-09-02">
<SAF>1</SAF>
<SAR>2</SAR>
</Date>
<DXLID>3</DXLID>
</Instrument>
</All>
</Response>
请注意:
如果第二个文档位于自己的文件中,则不会显示命名空间节点 - 为方便起见,它包含在当前转换中。
首先处理第一个文档的所有节点(如果其中一些节点在第二个文档中具有匹配的节点,则执行合并)。
最后,第二个文档中没有第一个文档中相应<Instrument>
个节点的所有<Instrument>
个节点都会被复制到输出中。
使用密钥识别两个文档中的匹配Date
个节点。