2011-09-27 44 views
2

我有一组的XML文件的工作文件与此类似:如何“泛化”的XML到XML的XSL转换具有不同的标签,但相同的基本结构

例输入文件:

<a-list> 
    <a-item key_field="unique1" other="foo"/> 
    <a-item key_field="unique2" other="foo"/> 
    ... 
</a-list> 

,我有一个转换,将这些文件合并到同一结构的单个文件。它生成包含从所有文件的<a-item>元件的相同的外水平元件(<a-list>),并丢弃重复实体(具有相同key_field实体)。我现在面对其他几组文件,每个文件的顶层结构都非常相似,我需要执行几乎相同的合并。

例如,这些文件可能是这样的:

<b-list> 
    <b-item different_key_field="unique93" other="foo"/> 
    <b-item different_key_field="unique94" other="foo"/> 
    ... 
</b-list> 

这些其他文件中都有不同的数据,但变换是一般同:我需要采取具有相同结构的多个输入文件(含有物品,其中该物品是唯一由密钥属性标识的列表的根级别),并且产生具有包含所有从每个输入文件的(唯一的)项目的顶级元素的输出文件。不幸的是,我的“合并”变换专门针对输入文件中的命名元素(例如,它具有<a-item>节点的模板,并且它专门查找重复的key_field属性)。复制变换,搜索/替换元素名称和关键属性名称相当简单,但对于每种类型的输入文件复制相同的代码似乎效率极低。唯一不同的是根元素的名称,item元素的名称和key属性的名称。我想要做的(合并)保持不变。

我怎么能写,可以不指定元素/属性的准确名称执行这种合并操作的,这样我就可以调用相同的变换,每种文件类型的转型?有没有办法接受根元素名称,项目元素名称和键属性名称作为参数?

作为附加的约束,我仅限于使用Xalan的,所以我相信,这意味着XSL 1.0只,这将是最好的,以避免任何扩展。

我想过转化与另一个XSL的XSL,但似乎颇为曲折这样一个简单的事情。

我试过在谷歌上搜索这里和周围的互联网,但我对XSL有点新,并且我认为搜索与XSL或XSLT关联的所有词语在XSL中似乎都有特定的含义上下文使得它们作为搜索条件(例如XSL模板,泛型XSL等)不太有用。一些词汇和一些好的链接会很棒,一个例子会很棒。

非常感谢, 拉斯

+0

实例文件之间是否有任何相同的内容?您可以为结构(例如'/ */*')进行更通用的匹配,但是如果您想根据某些属性获取不同的列表,那么这些属性实际上是否在名称中包含“key”,例如? –

回答

1

这里是一个完整的解决方案

<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:param name="pDoc1File" select="'b-list-file1.xml'"/> 
<xsl:param name="pDoc2File" select="'b-list-file2.xml'"/> 

<xsl:param name="pElemName" select="'b-item'"/> 
<xsl:param name="pKeyAttrName" select="'different_key_field'"/> 

<xsl:variable name="vDoc1" select="document($pDoc1File)"/> 
<xsl:variable name="vDoc2" select="document($pDoc2File)"/> 


<xsl:template match="/"> 
    <xsl:apply-templates select="$vDoc1/node()"/> 
</xsl:template> 

<xsl:template match="/*"> 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 
    <xsl:copy-of select= 
    "*[name()=$pElemName] 
     [not(@*[name()=$pKeyAttrName] 
     = 
     $vDoc2/*/*[name()=$pElemName] 
       /@*[name()=$pKeyAttrName]) 
     ]"/> 

    <xsl:copy-of select= 
    "$vDoc2/*/*[name()=$pElemName] 
     [not(@*[name()=$pKeyAttrName] 
     = 
     $vDoc1/*/*[name()=$pElemName] 
       /@*[name()=$pKeyAttrName]) 
     ]"/> 
    </xsl:copy> 
</xsl:template> 
</xsl:stylesheet> 

文件:B超单,file1.xml

<b-list> 
    <b-item different_key_field="unique93" other="foo"/> 
    <b-item different_key_field="unique94" other="foo"/> ... 
</b-list> 

文件:b-list-file2.xml

<b-list> 
    <b-item different_key_field="unique92" other="foo"/> 
    <b-item different_key_field="unique93" other="foo"/> ... 
</b-list> 

当这种转化是在任何XML文档(未使用/忽略)施加时,想要的,正确的结果产生

<b-list> 
    <b-item different_key_field="unique94" other="foo"/> 
    <b-item different_key_field="unique92" other="foo"/> 
</b-list> 

说明

  1. 要处理的文档的文件路径(URL)以全局(转换之外)参数提供。

  2. 元素的名称在全局参数中提供。

  3. “key”属性的名称作为全局/外部参数提供。

  4. 最后,在两个<xsl:copy-of>指令的select属性XPath表达式,使用的参数的值来选择适当命名的元素和属性。

请注意:每一个XSLT处理器都有自己的执行设置和参数传递给改造。在Xalan文档中阅读此内容。

+0

谢谢,我所缺少的是使用通配符匹配(例如match =“/ *”和match =“/ */*”)的想法,所以它可以处理任何文档。我可能没有100%清楚合并的具体细节,但我很积极,我可以从这里拿走它!谢谢! –

+0

@RussM:不客气。 –

0

那么你可以用参数解决您的问题。例如,没有像C++模板那样的模板化xsl的概念,但使用参数可以实现这种效果。例如,我的一个xslt文件如下所示:

<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:space="preserve" version="2.0"> 
<!--Output type to be used with the xsl:result-document--> 
<xsl:output name="html" encoding="utf-8" method="html" indent="yes" doctype- system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/> 
<!--Global output type--> 
<xsl:output encoding="utf-8" method="html" indent="yes" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/> 
<!--xml output--> 
<xsl:output name="xml" encoding="utf-8" method="xml" indent="yes"/> 
<xsl:param name="sapFile" as="xs:string" required="yes"/> 
<xsl:param name="automaticDate" as="xs:string" required="yes"/> 
<xsl:param name="generatePDF" as="xs:string" required="yes"/> 
<xsl:param name="fileName" as="xs:string" required="yes"/> 
. 
. 
. 

这里的重要元素是xsl:param。您可以在“调用”xsl转换时传递这些参数。在你的情况下,这些参数是例如:在一个例子中是a列表,在另一个例子中是b列表等。然后你可以在你想要的xslt代码中使用这些参数,如$param,这样你就可以实现通用性。

我希望给你一些指点:)

相关问题