我是XSLT的新手,我需要将xslt脚本插入第三方软件,该软件使用XSLT 1.0转换xml文档。
我的任务是获取文档A.xml并插入文档B.xml中的每个元素,但前提是A中的文本尚不存在。输出应该生成为文档C.xml。
示例A.xml:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<Table>
<Name>SCHAME.table_name</Name>
<Location>oracle:TNS_1</Location>
<Citation>
<Title>Title 1</Title>
<Description/>
</Citation>
<metadataDate>20170418</metadataDate>
</Table>
</metadata>
示例B.xml:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<Table>
<Citation>
<Title>Template Title</Title>
<Abstract>Template Abstract</Abstract>
<Description>Template Description</Description>
</Citation>
<MetadataDate>20160131</MetadataDate>
</Table>
</metadata>
C.xml的预期输出是:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<Table>
<Name>SCHAME.table_name</Name>
<Location>oracle:TNS_1</Location>
<Citation>
<Title>Title 1</Title>
<Abstract>Template Abstract</Abstract>
<Description>Template Description</Description>
</Citation>
<metadataDate>20170418</metadataDate>
</Table>
</metadata>
有三件事是重要的:
我不需要正在运行的解决方案,任何提示如何为XSLT初学者解决这个问题都会很好。
答案 0 :(得分:0)
此处的问题是如何识别两个文件中的对应的元素。我假设每个元素最多出现一次,因此我们可以简单地通过元素名称来识别相应的元素。 我的解决方案遵循John Bollinger的想法:
这是我使用的模板:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Parameters -->
<xsl:param name="aFile" select="'a.xml'" />
<xsl:param name="bFile" select="'b.xml'" />
<!-- Variables -->
<xsl:variable name="aDoc" select="document( $aFile, . )"/>
<xsl:variable name="bDoc" select="document( $bFile, . )"/>
<!-- Locate elements by name in both files -->
<xsl:key name="elementsByName" match="*" use="name()" />
<!-- Root-Template -->
<xsl:template match="/">
<xsl:comment>
<xsl:value-of select="concat( 'Merge of ', $aFile, ' with ', $bFile )" />
</xsl:comment>
<xsl:apply-templates />
</xsl:template>
<!-- Merge all elements -->
<xsl:template match="*">
<xsl:variable name="elemName" select="name()" />
<xsl:variable name="aValue" select="$aDoc/key('elementsByName', $elemName)/text()" />
<xsl:variable name="bValue" select="$bDoc/key('elementsByName', $elemName)/text()" />
<xsl:copy>
<xsl:choose>
<xsl:when test="$aValue != ''">
<xsl:value-of select="$aValue" />
</xsl:when>
<xsl:when test="$bValue != ''">
<xsl:value-of select="$bValue" />
</xsl:when>
</xsl:choose>
<xsl:apply-templates select="*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
以下XSL将上述模板作为输入:
<?xml version="1.0" encoding="UTF-8"?>
<!--Merge of a.xml with b.xml-->
<metadata>
<Table>
<Name>SCHAME.table_name</Name>
<Location>oracle:TNS_1</Location>
<Citation>
<Title>Title 1</Title>
<Abstract>Template Abstract</Abstract>
<Description>Template Description</Description>
</Citation>
<metadataDate>20170418</metadataDate>
</Table>
</metadata>
转型的结果是:
xsl:key
唯一的&#34;技巧&#34;在此代码中使用key()
和相应的xsl:copy
函数。这允许我们在文件A和B中找到相应的元素(相同的名称)。
此脚本将模板中的所有元素复制到输出文件C.
要更改此行为,只需移动xsl:when
内的{{1}}指令 。
答案 1 :(得分:0)
我尝试单独给出一个改进的答案,以避免与那里的有用评论混淆。
除了那里的“通用”方法(匹配元素名称)之外,我们现在也有特定的模板。
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Parameters -->
<xsl:param name="aFile" select="'a.xml'" />
<xsl:param name="bFile" select="'b.xml'" />
<!-- Variables -->
<xsl:variable name="aDoc" select="document( $aFile, . )"/>
<xsl:variable name="bDoc" select="document( $bFile, . )"/>
<!-- Locate elements by name in both files -->
<xsl:key name="elementsByName" match="*" use="name()" />
<!-- Root-Template -->
<xsl:template match="/">
<xsl:comment>
<xsl:value-of select="concat( 'Merge of ', $aFile, ' with ', $bFile )" />
</xsl:comment>
<xsl:apply-templates />
</xsl:template>
<!-- Merge specific elements -->
<xsl:template match="metadata/Table/Description">
<xsl:call-template name="mergeElement">
<xsl:with-param name="aValue" select="$aDoc/metadata/Table/Description/text()" />
<xsl:with-param name="bValue" select="$bDoc/metadata/Table/Description/text()" />
</xsl:call-template>
</xsl:template>
<xsl:template match="metadata/Table/Citation/Description">
<xsl:call-template name="mergeElement">
<xsl:with-param name="aValue" select="$aDoc/metadata/Table/Citation/Description/text()" />
<xsl:with-param name="bValue" select="$bDoc/metadata/Table/Citation/Description/text()" />
</xsl:call-template>
</xsl:template>
<!-- Merge unique elements -->
<xsl:template match="*" priority="-10">
<xsl:variable name="elemName" select="name()" />
<xsl:call-template name="mergeElement">
<xsl:with-param name="aValue" select="$aDoc/key('elementsByName', $elemName)/text()" />
<xsl:with-param name="bValue" select="$bDoc/key('elementsByName', $elemName)/text()" />
</xsl:call-template>
</xsl:template>
<!-- Use A or B -->
<xsl:template name="mergeElement">
<xsl:param name="aValue" />
<xsl:param name="bValue" />
<xsl:copy>
<xsl:choose>
<xsl:when test="$aValue != ''">
<xsl:value-of select="$aValue" />
</xsl:when>
<xsl:when test="$bValue != ''">
<xsl:value-of select="$bValue" />
</xsl:when>
</xsl:choose>
<xsl:apply-templates select="*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
对于测试,我更改了模板和A和B,并在Table中直接添加了另一个Description元素:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<Table>
<Name />
<Description/> <!-- NEW: not unique element name -->
<Location/>
<Citation>
<Title />
<Abstract />
<Description/>
</Citation>
<metadataDate/>
</Table>
</metadata>
档案A:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<Table>
<Name>SCHAME.table_name</Name>
<Location>oracle:TNS_1</Location>
<Description>Table description A</Description> <!-- NEW -->
<Citation>
<Title>Title 1</Title>
<Description/>
</Citation>
<metadataDate>20170418</metadataDate>
</Table>
</metadata>
档案B:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<Table>
<Description>Table description B</Description> <!-- NEW -->
<Citation>
<Title>Template Title</Title>
<Abstract>Template Abstract</Abstract>
<Description>Template Description</Description>
</Citation>
<MetadataDate>20160131</MetadataDate>
</Table>
</metadata>
生成的文件C:
<?xml version="1.0" encoding="UTF-8"?>
<!--Merge of a.xml with b.xml-->
<metadata>
<Table>
<Name>SCHAME.table_name</Name>
<Description>Table description A</Description> <!-- NEW -->
<Location>oracle:TNS_1</Location>
<Citation>
<Title>Title 1</Title>
<Abstract>Template Abstract</Abstract>
<Description>Template Description</Description>
</Citation>
<metadataDate>20170418</metadataDate>
</Table>
</metadata>
显然,这不是一般的解决方案。 但是,如果非唯一元素的数量与总数相比较低,您将受益于通用模板。只有非独特元素必须单独“设置”。