嵌套XML的XSL转换

时间:2015-04-07 11:41:21

标签: xslt

我是XSLT世界的新手。我在这里发现了一些有帮助的线索,但由于我并不真正理解我在做什么,所以我有点卡住了。我试图循环并格式化一些嵌套的XML。

我的XML

<?xml version="1.0" encoding="UTF-8"?>
<exchange>
<vco>
<vco.srs>
<vco_crsc.vco.srs>BUUBMS</vco_crsc.vco.srs>
<vco_prgc.vco.srs>BUBSBAT02</vco_prgc.vco.srs>
<vco_rouc.vco.srs>USMANG</vco_rouc.vco.srs>
<cbo>
<cbo.srs>
<cbo_occl.cbo.srs>AJ</cbo_occl.cbo.srs>
</cbo.srs>
<cbo.srs>
<cbo_occl.cbo.srs>FJ</cbo_occl.cbo.srs>
</cbo.srs>
</cbo>
</vco.srs>
</vco>
</exchange>

通过阅读另一篇类似的帖子,我创建了一个基于模板的代码。模板功能,但理想情况下我希望它的格式不同,因为模板会丢失字段格式。假设我需要另一个模板定义,但正如我所说,不确定我在做什么!

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="/root">
<ImportTask>
<xsl:apply-templates select="CourseDetails"/>-<xsl:apply-templates select="CourseOcc"/>
</ImportTask>       
</xsl:template>

<xsl:template match="CourseDetails">
<Courses>
<xsl:for-each select="exchange/vco/vco.srs">
<Course>
<CourseCode><xsl:value-of select="vco_crsc.vco.srs"/></CourseCode>-<Programmecode><xsl:value-of select="vco_prgc.vco.srs"/></Programmecode>-<Routecode><xsl:value-of select="vco_rouc.vco.srs"/></Routecode>
</Course>
</xsl:for-each>
</Courses>
</xsl:template>
<xsl:template match="CourseOcc">
<Occurences>
<xsl:for-each select="exchange/cbo/cbo.srs">
<Occur>
<OccurCode><xsl:value-of select="cbo_occl.cbo.srs"/></OccurCode>
</Occur>
</xsl:for-each>
</Occurences>
</xsl:template>
</xsl:stylesheet>

这是输出:     

BUUBMS
BUBSBAT02
USMANG


AJ


FJ

这一切都非常好但不是我想要的。 理想情况下,我希望输出为:

    <ImportTask>
    <Courses>
    <Course>BUUBMS-BUBSBAT02-USMANG-AJ</Course>
    <Course>BUUBMS-BUBSBAT02-USMANG-FJ<Course>
    </Courses>
   </ImportTask>

我猜我需要设置更多的模板代码,但我不确定究竟是什么?

有人能指出我正确的方向还是告诉我是否有更好的方法?

非常感谢

2 个答案:

答案 0 :(得分:0)

以下xslt将您的输入传输到所需的输出。在那里,只使用了两个模板,一个用于根元素,一个用于<cbo_occl.cbo.srs>。后者选择以&#34; vco _&#34;开头的元素的文本节点。在该元素之前,将它们连接起来并最终打印出自己的内容。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes" method="xml"/>

    <xsl:template match="/exchange">
        <ImportTask>
            <Courses>
                <xsl:apply-templates select="//cbo_occl.cbo.srs"/>
            </Courses>
        </ImportTask>
    </xsl:template>

    <xsl:template match="cbo_occl.cbo.srs">
        <Course>
            <!-- select all text-Nodes of vco_* elements -->
            <xsl:for-each select="../../../*[matches(name(),'^vco_.*')]/text()">
                <xsl:value-of select="concat(.,'-')"/>
            </xsl:for-each>
            <xsl:value-of select="."/>
        </Course>        
    </xsl:template>

</xsl:stylesheet>    

答案 1 :(得分:0)

您的XSLT中有许多不同的模板匹配

<xsl:template match="/root">

<xsl:template match="CourseDetails">

<xsl:template match="CourseOcc">

但是,当您使用具有匹配项的模板时,这些模板仅在与输入XML文档中的节点匹配时才适用。你不能在这里使用任意名称。因为您的输入XML没有名为rootCourseDetailsCourseOcc的元素,所以这些模板永远不会被调用。

您获得当前输出的原因是由于XSLT的built-in template规则,当您自己的XSLT中没有匹配的模板模板时(这种情况就是这种情况)适用。

我认为您尝试做的事实上是通过“命名”模板实现的,这将允许您使用任意名称。因此,您的XSLT将更加正确地编写:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="/">
    <ImportTask>
        <xsl:call-template name="CourseDetails"/>
        <xsl:text>-</xsl:text>
        <xsl:call-template name="CourseOcc"/>
    </ImportTask>       
</xsl:template>

<xsl:template name="CourseDetails">
    <Courses>
        <xsl:for-each select="exchange/vco/vco.srs">
            <Course>
                <CourseCode><xsl:value-of select="vco_crsc.vco.srs"/></CourseCode>
                <xsl:text>-</xsl:text>
                <Programmecode><xsl:value-of select="vco_prgc.vco.srs"/></Programmecode>
                <xsl:text>-</xsl:text>
                <Routecode><xsl:value-of select="vco_rouc.vco.srs"/></Routecode>
            </Course>
        </xsl:for-each>
    </Courses>
</xsl:template>

<xsl:template name="CourseOcc">
    <Occurences>
        <xsl:for-each select="exchange/cbo/cbo.srs">
            <Occur>
                <OccurCode><xsl:value-of select="cbo_occl.cbo.srs"/></OccurCode>
            </Occur>
        </xsl:for-each>
    </Occurences>
</xsl:template>
</xsl:stylesheet>

注意第一个模板仍然是模板匹配,但是匹配/而不是/root,其中/代表“文档节点”。这是XSLT首先匹配的模板。

话虽如此,您实际上并不需要在此处使用命名模板。您可以通过常规模板匹配实现所需的功能。在这种情况下,这种XSLT可能更可取

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

<xsl:template match="/exchange">
    <ImportTask>
        <Courses>
            <xsl:apply-templates select="vco/vco.srs"/>
        </Courses>
        <xsl:if test="cbo/cbo.srs">
            <xsl:text>-</xsl:text>
            <Occurences>
                <xsl:apply-templates select="cbo/cbo.srs"/>
            </Occurences>
        </xsl:if>
    </ImportTask>       
</xsl:template>

<xsl:template match="vco.srs">
    <Course>
        <CourseCode><xsl:value-of select="vco_crsc.vco.srs"/></CourseCode>
        <xsl:text>-</xsl:text>
        <Programmecode><xsl:value-of select="vco_prgc.vco.srs"/></Programmecode>
        <xsl:text>-</xsl:text>
        <Routecode><xsl:value-of select="vco_rouc.vco.srs"/></Routecode>
    </Course>
</xsl:template>

<xsl:template match="cbo.srs">
    <Occur>
        <OccurCode><xsl:value-of select="cbo_occl.cbo.srs"/></OccurCode>
    </Occur>
</xsl:template>
</xsl:stylesheet>