我有两个xml文件。
档案1 -
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<School>
<section id="12" name="Apple"/>
<section id="50" name="Newton"/>
</School>
<Students>
<roll no="111" name="Smith"/>
<roll no="122" name="Alan"/>
<roll no="20" name="Bruce"/>
</Students>
<Teachers>
<Math>
<emp id="55" name="Karen"/>
<emp id="2" name="David"/>
</Math>
<Science>
<emp id="1" name="Thomas"/>
</Science>
</Teachers>
<Sports>
<Indoor>
<Boardgame>
<game id="12" name="Chess"/>
</Boardgame>
<Arcade>
<game id="3" name="Car Racing"/>
</Arcade>
</Indoor>
<Outdoor>
<Field>
<game id="1" name="Football"/>
<game id="100" name="Cricket"/>
</Field>
<Court>
<game id="2" name="Tennis"/>
</Court>
</Outdoor>
</Sports>
</Root>
档案2 -
<?xml version="1.0" encoding="UTF-8"?>
<Updates>
<School>
<section id="12" name="Orange"/>
</School>
<Students>
<roll no="122" name="Sam"/>
</Students>
<Teachers>
<Math>
<emp id="300" name="Steve" />
</Math>
</Teachers>
<Sports>
<Indoor>
<Boardgame>
<game id="37" name="Monopoly"/>
</Boardgame>
<Boardgame2>
<game id="36" name="Ludo"/>
</Boardgame2>
</Indoor>
<Outdoor>
<Field>
<game id="1" name="Football"/>
<game id="100" name="Bull Fighting"/>
</Field>
<Court>
<game id="19" name="Badminton"/>
</Court>
</Outdoor>
<Computer>
<game id="10" name="AOE" />
</Computer>
</Sports>
</Updates>
我需要合并文件,以便获得以下输出。如果id / no匹配,file2中的条目将覆盖file1中的条目。在适当的层次结构下的输出中,将根据需要添加新元素。
转型输出 -
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<School>
<section id="12" name="Orange"/>
<section id="50" name="Newton"/>
</School>
<Students>
<roll no="111" name="Smith"/>
<roll no="122" name="Sam"/>
<roll no="20" name="Bruce"/>
</Students>
<Teachers>
<Math>
<emp id="55" name="Karen"/>
<emp id="2" name="David"/>
<emp id="300" name="Steve" />
</Math>
<Science>
<emp id="1" name="Thomas"/>
</Science>
</Teachers>
<Sports>
<Indoor>
<Boardgame>
<game id="12" name="Chess"/>
<game id="37" name="Monopoly"/>
</Boardgame>
<Arcade>
<game id="3" name="Car Racing"/>
</Arcade>
<Boardgame2>
<game id="36" name="Ludo"/>
</Boardgame2>
</Indoor>
<Outdoor>
<Field>
<game id="1" name="Football"/>
<game id="100" name="Bull Fighting"/>
</Field>
<Court>
<game id="2" name="Tennis"/>
<game id="19" name="Badminton"/>
</Court>
</Outdoor>
<Computer>
<game id="10" name="AOE" />
</Computer>
</Sports>
</Root>
下面是XSLT,但它仅适用于更新,而不适用于插入。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/">
<xsl:apply-templates select="node()">
<xsl:with-param name="doc-context" select="document('file2.xml')/node()" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="node()">
<xsl:param name="doc-context" />
<xsl:variable name="id" select="@id" />
<xsl:variable name="no" select="@no" />
<xsl:copy>
<xsl:copy-of select="@*|$doc-context[@id = $id or @no = $no]/@*" />
<xsl:apply-templates select="node()">
<xsl:with-param name="doc-context" select="$doc-context/node()" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
我稍后会写一个完整的样式表,但是现在,我将用这个方法来解决这个问题....
您可以在步骤2和5中使用xsl:key和key()函数进行测试。但要注意新手的常见陷阱:2-arity key()函数具有焦点文档的隐式参数。
怎么样......
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:so="http://stackoverflow.com/questions/34522017"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0"
exclude-result-prefixes="so xs">
<xsl:output omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:param name="updates-file" as="xs:string" />
<xsl:strip-space elements="*" />
<xsl:variable name="updates" select="doc($updates-file)" />
<xsl:function name="so:merge-key" as="xs:string">
<xsl:param name="ele" as="element()" />
<!-- Updates and Root are at the same for merging purposes. -->
<xsl:variable name="ele-name" select="local-name($ele[not(self::Updates)][not(self::Root)])" />
<xsl:value-of select="concat( $ele-name, '!', $ele/@id, $ele/@no)" />
</xsl:function>
<xsl:template match="@*|comment()|processing-instruction()|text()">
<xsl:copy />
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/Root">
<xsl:apply-templates select="." mode="update">
<xsl:with-param name="peer-updates" select="$updates/Updates" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[not(@id|@no)]" mode="update">
<xsl:param name="peer-updates" as="element()*" />
<xsl:variable name="this-key" select="so:merge-key(.)" />
<xsl:variable name="compare-set" select="*" as="element()*" />
<xsl:variable name="merge-other" select="$peer-updates[so:merge-key(.) eq $this-key]/*" as="element()*" />
<xsl:copy>
<!-- Process the fluff. -->
<xsl:apply-templates select="@*|comment()|processing-instruction()|text()" />
<!-- Now the unchanged orginal elements. -->
<xsl:apply-templates select="*[not( so:merge-key(.) = $merge-other/so:merge-key(.))]" />
<!-- Now the updated elements. -->
<xsl:apply-templates select="*[so:merge-key(.) = $merge-other/so:merge-key(.)]" mode="update">
<xsl:with-param name="peer-updates" select="$merge-other[so:merge-key(.) = $compare-set/so:merge-key(.)]" />
</xsl:apply-templates>
<!-- Now new elements. -->
<xsl:apply-templates select="$merge-other[ not( so:merge-key(.) = $compare-set/so:merge-key(.))]" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[@id|@no]" mode="update">
<xsl:param name="peer-updates" as="element()*" />
<xsl:variable name="this-key" select="so:merge-key(.)" />
<xsl:variable name="merge-other" select="$peer-updates[so:merge-key(.) eq $this-key]" as="element()?" />
<xsl:copy-of select="if ($merge-other) then $merge-other else ." />
</xsl:template>
</xsl:transform>
updates-file
指定更新文档的URI。传递此实际参数值。 OP要求更改订购规则。这是一个快速而又脏的变更,强制执行指定的排序规则。将带有注释Now the unchanged original elements.
和Now the updated elements.
的两个序列构造函数替换为这一个...
<!-- For the original elements, both unchanged and to be updated. -->
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="so:merge-key(.) = $merge-other/so:merge-key(.)">
<xsl:apply-templates select="." mode="update">
<xsl:with-param name="peer-updates" select="$merge-other[so:merge-key(.) = $compare-set/so:merge-key(.)]" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
一般来说,xsl:for-each
是丑陋而糟糕的。它是一个xslt反模式。如果这是我的生产代码,并且我有更多时间考虑它,我将使用模板匹配机制。但是对于它的价值,无论如何,这是一个快速而肮脏的解决方案。