简体   繁体   English

借助 xslt 合并多个 xml 文件

[英]Merging multiple xml files with help of xslt

List of Input files will be passed to XSLT from java code.输入文件列表将从 java 代码传递给 XSLT。 I am using tokenizer to split the input files and get coordinator nodes from all input files and append into resultant file我正在使用标记器拆分输入文件并从所有输入文件中获取协调器节点并附加到结果文件中

<xsl:param name="listOfFiles"/>


<xsl:template match="/*">
        <xsl:for-each select="tokenize($listOfFiles, ',')">
            <xsl:variable name="fileName" select="."/>
            <xsl:variable name="updates" select="document($fileName)" />
            <xsl:variable name="updateItems" select="$updates/bundle-app/coordinator" />
                <xsl:copy>
                    <xsl:apply-templates select="$updateItems" />
                </xsl:copy>
        </xsl:for-each>
</xsl:template>

My result file just prints the file names passed to listOfFiles instead of coordinator nodes in the files.我的结果文件只打印传递给 listOfFiles 的文件名,而不是文件中的协调器节点。 Working XSLT with one file使用一个文件处理 XSLT

<xsl:param name="discoveryFile"/>
<xsl:param name="updates" select="document($discoveryFile)" />
<xsl:variable name="updateItems" select="$updates/bundle-app/coordinator" />
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="/*">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()[not(self::coordinator)] |
                               coordinator[not(id = $updateItems/id)]" />
        <xsl:apply-templates select="$updateItems" />
    </xsl:copy>
</xsl:template>

I am very new to XSLT Please suggest a way to proceed with the list of files.我对 XSLT 非常陌生 请提出一种处理文件列表的方法。

Within an xsl:for-each instruction, the context item is set to each member of the selected sequence in turn.xsl:for-each指令中,上下文项依次设置为所选序列的每个成员。 Importantly, your xsl:for-each is selecting a sequence of string values .重要的是,您的xsl:for-each正在选择一系列字符串值 This is perfectly acceptable, but it does mean that within your xsl:for-each , the context item will be a string value.这是完全可以接受的,但这确实意味着在您的xsl:for-each ,上下文项将是一个字符串值。 This has an important effect on the behavior of the xsl:copy instruction you're using.这对您使用的xsl:copy指令的行为有重要影响。

xsl:copy will copy whatever the current context item is, so it is copying each of your tokenized file names to the output, as you observed. xsl:copy将复制当前上下文项的任何内容,因此正如您所观察到的那样,它会将您的每个标记化文件名复制到输出中。 However, xsl:copy is allowed to contain a sequence constructor , as yours does:但是, xsl:copy允许包含序列构造函数,就像您的一样:

<xsl:copy>
  <!-- The instructions here within the xsl:copy element are a sequence constructor -->
  <xsl:apply-templates select="$updateItems" />
</xsl:copy>

The issue is that a sequence constructor within xsl:copy is only used if the context item is an element or a document node (see section 7.5 of the XSLT 1.0 spec ).问题在于xsl:copy中的序列构造函数仅在上下文项是元素或文档节点时才使用(请参阅XSLT 1.0 规范的第 7.5 节)。 Since the context item in this case is an string value, nothing is done with the result of the xsl:apply-templates instruction.由于本例中的上下文项是一个字符串值,因此xsl:apply-templates指令的结果没有做任何事情。 (In fact, the processor may not even be evaluating this instruction since it can tell it will have no effect on the output.) (事实上​​,处理器甚至可能不会评估这条指令,因为它可以判断它不会对输出产生影响。)

It seems you really just want to apply templates to the nodes you've selected from each file, not copy the context item at any point.看来您真的只想将模板应用于您从每个文件中选择的节点,而不是在任何时候复制上下文项。 So this is probably what you want:所以这可能是你想要的:

<xsl:param name="listOfFiles"/>

<xsl:template match="/*">
  <xsl:for-each select="tokenize($listOfFiles, ',')">
    <xsl:variable name="fileName" select="."/>
    <xsl:variable name="updates" select="document($fileName)" />
    <xsl:variable name="updateItems" select="$updates/bundle-app/coordinator" />
    <xsl:apply-templates select="$updateItems" />
  </xsl:for-each>
</xsl:template>

This assumes you have either an identity template defined in your stylesheet, or some other templates meant to further process the coordinator elements.这假设您在样式表中定义了一个标识模板,或者其他一些用于进一步处理coordinator元素的模板。 If your intent is really just to merge them unchanged into an aggregate document, then you could replace <xsl:apply-templates select="$updateItems" /> with <xsl:copy-of select="$updateItems" /> .如果您的意图真的只是将它们原封不动地合并到一个聚合文档中,那么您可以将<xsl:apply-templates select="$updateItems" />替换为<xsl:copy-of select="$updateItems" />

XSLT file that worked for my requirement符合我的要求的 XSLT 文件

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>


    <xsl:param name="tempFiles"/>

    <xsl:template match="/">
        <xsl:copy>
            <xsl:apply-templates mode="rootcopy"/>
        </xsl:copy>
    </xsl:template>

    <!-- Deep copy template -->
    <xsl:template match="@* | node()" mode="copy">
        <xsl:copy>
            <xsl:apply-templates mode="copy" select="@*"/>
            <xsl:apply-templates mode="copy"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/*" mode="rootcopy">
        <xsl:copy>
            <xsl:apply-templates mode="copy" select="/bundle-app/*"/>
            <xsl:for-each select="tokenize($tempFiles, ',')">
                <xsl:variable name="fileName" select="."/>
                <xsl:variable name="updates" select="document($fileName)" />
                <xsl:variable name="updateItems" select="$updates/bundle-app/*" />
                <xsl:apply-templates mode="copy" select="$updateItems"/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM