如何为两个 xml 文件添加合并模板?
How to add a merge template for two xml files?
第一个 xml 文件 in.xml:
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1 />
<s>
<m2 />
<Item key="1">
<m3 />
<sp>
<Chart />
</sp>
</Item>
<m4 />
<Item key="2">
<sp>
<m5 />
<Chart />
</sp>
</Item>
<Item key="3">
<sp>
<Chart />
</sp>
</Item>
<m6 />
</s>
</Item>
</c>
</conf>
第二个 xml 文件 profile.xml,它完成了第一个包含小部件信息的文件:
<p title="profile">
<c>
<Item key="db">
<s>
<Item key="1">
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="2">
<sp>
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
</s>
</Item>
</c>
</p>
profile.xml文件与in.xml的区别在于根标签名称不同,每个Chart标签都有对应的子Widget标签,只有相对于Chart标签的父标签存在于文件和除root和Widget之外的所有标签都只有键属性。
转换后的文件与原始文件仅在 Chart 标签的 Widget 子标签不同:
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1 />
<s>
<m2 />
<Item key="1">
<m3 />
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<m4 />
<Item key="2">
<sp>
<m5 />
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
<m6 />
</s>
</Item>
</c>
</conf>
现在有一个不完整的 XSLT1.0 转换文件:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:param name="updates" select="document($fileName)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如何重写“p”模板XSLT1.0?
试试这个:
convert.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:param name="updates" select="document($fileName)" />
<!--transform starts here on input XML-->
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!--rules for general nodes()-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!--special rule for Chart elements-->
<xsl:template match="Chart">
<xsl:variable name="context" select="."/>
<xsl:if test="$updates//Item/@key = $context/ancestor-or-self::Item[1]/@key">
<xsl:copy-of select="($updates//Item[@key = $context/ancestor-or-self::Item[1]/@key])//Chart"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
output.xml
<?xml version="1.0" encoding="UTF-8"?>
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1/>
<s>
<m2/>
<Item key="1">
<m3/>
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<m4/>
<Item key="2">
<sp>
<m5/>
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
<m6/>
</s>
</Item>
</c>
</conf>
如果需要,您可以将参数 profile.xml
更改为其他参数...
不使用密钥
如果您的属性 @attr01-@attr03 很重要?:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:variable name="updates" select="document($fileName)/*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Chart">
<xsl:variable name="idattr01" select="ancestor::*[@attr01]/@attr01"/>
<xsl:variable name="idattr02" select="ancestor::*[@attr02]/@attr02"/>
<xsl:variable name="idattr03" select="ancestor::*[@attr03]/@attr03"/>
<xsl:variable name="key" select="ancestor::*[@key][1]/@key"/>
<xsl:variable name="chartFromUpdate" select="$updates[@attr01=$idattr01]/c[@attr02=$idattr02]/Item[@attr03=$idattr03]/s/Item[@key=$key]/sp/Chart" />
<xsl:choose>
<xsl:when test="$chartFromUpdate">
<xsl:copy-of select="$chartFromUpdate"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
或者您也可以这样使用 key-function:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:variable name="updates" select="document($fileName)" />
<xsl:key name="item" match="Item" use="@key"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Chart">
<xsl:variable name="key" select="ancestor::*[@key][1]/@key"/>
<xsl:variable name="chartFromUpdate">
<!-- Since the lookup is in an different document we have to change the context -->
<xsl:for-each select="$updates">
<xsl:copy-of select="key('item', $key)/sp/Chart"/>
</xsl:for-each>
</xsl:variable>
<xsl:choose>
<xsl:when test="$chartFromUpdate">
<xsl:copy-of select="$chartFromUpdate"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
关于在使用 xslt 1.0 的不同文档上使用 key-function,请参阅 this answer
对于两个 xslt,这是输出:
<?xml version="1.0" encoding="UTF-8"?>
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1/>
<s>
<m2/>
<Item key="1">
<m3/>
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<m4/>
<Item key="2">
<sp>
<m5/>
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
<m6/>
</s>
</Item>
</c>
</conf>
第一个 xml 文件 in.xml:
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1 />
<s>
<m2 />
<Item key="1">
<m3 />
<sp>
<Chart />
</sp>
</Item>
<m4 />
<Item key="2">
<sp>
<m5 />
<Chart />
</sp>
</Item>
<Item key="3">
<sp>
<Chart />
</sp>
</Item>
<m6 />
</s>
</Item>
</c>
</conf>
第二个 xml 文件 profile.xml,它完成了第一个包含小部件信息的文件:
<p title="profile">
<c>
<Item key="db">
<s>
<Item key="1">
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="2">
<sp>
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
</s>
</Item>
</c>
</p>
profile.xml文件与in.xml的区别在于根标签名称不同,每个Chart标签都有对应的子Widget标签,只有相对于Chart标签的父标签存在于文件和除root和Widget之外的所有标签都只有键属性。
转换后的文件与原始文件仅在 Chart 标签的 Widget 子标签不同:
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1 />
<s>
<m2 />
<Item key="1">
<m3 />
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<m4 />
<Item key="2">
<sp>
<m5 />
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
<m6 />
</s>
</Item>
</c>
</conf>
现在有一个不完整的 XSLT1.0 转换文件:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:param name="updates" select="document($fileName)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如何重写“p”模板XSLT1.0?
试试这个:
convert.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:param name="updates" select="document($fileName)" />
<!--transform starts here on input XML-->
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!--rules for general nodes()-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!--special rule for Chart elements-->
<xsl:template match="Chart">
<xsl:variable name="context" select="."/>
<xsl:if test="$updates//Item/@key = $context/ancestor-or-self::Item[1]/@key">
<xsl:copy-of select="($updates//Item[@key = $context/ancestor-or-self::Item[1]/@key])//Chart"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
output.xml
<?xml version="1.0" encoding="UTF-8"?>
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1/>
<s>
<m2/>
<Item key="1">
<m3/>
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<m4/>
<Item key="2">
<sp>
<m5/>
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
<m6/>
</s>
</Item>
</c>
</conf>
如果需要,您可以将参数 profile.xml
更改为其他参数...
不使用密钥
如果您的属性 @attr01-@attr03 很重要?:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:variable name="updates" select="document($fileName)/*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Chart">
<xsl:variable name="idattr01" select="ancestor::*[@attr01]/@attr01"/>
<xsl:variable name="idattr02" select="ancestor::*[@attr02]/@attr02"/>
<xsl:variable name="idattr03" select="ancestor::*[@attr03]/@attr03"/>
<xsl:variable name="key" select="ancestor::*[@key][1]/@key"/>
<xsl:variable name="chartFromUpdate" select="$updates[@attr01=$idattr01]/c[@attr02=$idattr02]/Item[@attr03=$idattr03]/s/Item[@key=$key]/sp/Chart" />
<xsl:choose>
<xsl:when test="$chartFromUpdate">
<xsl:copy-of select="$chartFromUpdate"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
或者您也可以这样使用 key-function:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="fileName" select="'profile.xml'" />
<xsl:variable name="updates" select="document($fileName)" />
<xsl:key name="item" match="Item" use="@key"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Chart">
<xsl:variable name="key" select="ancestor::*[@key][1]/@key"/>
<xsl:variable name="chartFromUpdate">
<!-- Since the lookup is in an different document we have to change the context -->
<xsl:for-each select="$updates">
<xsl:copy-of select="key('item', $key)/sp/Chart"/>
</xsl:for-each>
</xsl:variable>
<xsl:choose>
<xsl:when test="$chartFromUpdate">
<xsl:copy-of select="$chartFromUpdate"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
关于在使用 xslt 1.0 的不同文档上使用 key-function,请参阅 this answer
对于两个 xslt,这是输出:
<?xml version="1.0" encoding="UTF-8"?>
<conf title="co" attr01="val01">
<c attr02="val02">
<Item key="db" attr03="val03">
<m1/>
<s>
<m2/>
<Item key="1">
<m3/>
<sp>
<Chart>
<Widget title="widget12">
<Test title="test1"/>
</Widget>
</Chart>
</sp>
</Item>
<m4/>
<Item key="2">
<sp>
<m5/>
<Chart>
<Widget title="widget32">
<Test title="test3"/>
</Widget>
</Chart>
</sp>
</Item>
<Item key="3">
<sp>
<Chart>
<Widget title="widget54">
<Test title="test6"/>
</Widget>
</Chart>
</sp>
</Item>
<m6/>
</s>
</Item>
</c>
</conf>