XSLT:使用一个属性合并两个标签,使用转换/映射合并另一个标签

时间:2013-02-25 15:12:53

标签: xslt

我在输入文件中有两个标签,变量和类型:

<variable baseType="int" name="X">
</variable>

<type baseType="structure" name="Y">
    <variableInstance name="X" />
</type>

我需要生成以下输出文件:

<Item name="Y">
    <Field name="X" type="Long" />
</Item>

所以从概念上讲,我的方法是将类型标签转换为Item tage,将变量实例转换为Field。这工作正常:

<xsl:for-each select="type[@baseType='structure']">
    <Item>
        <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
        <xsl:for-each select="variableInstance">
            <Field>
                <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
                <xsl:attribute name="type">**THIS IS WHERE I'M STUCK**</xsl:attribute>
            </Field>
        </xsl:for-each>
    </Item>
</xsl:for-each>

我坚持的问题是:

  1. 我不知道如何通过名称让变量标签上的variableInstance / Field标签匹配,所以我可以访问baseType。
  2. 一旦我能够做到1,我需要将“int”映射到“Long”。
  3. 提前致谢!

2 个答案:

答案 0 :(得分:1)

问题1。

对于您遇到的第一个问题,您可以使用密钥:

<xsl:key name="variable-key" match="//variable" use="@name" />

该密钥将使用其名称索引文档中的所有变量元素。现在,我们可以使用以下XPath表达式访问这些元素中的任何一个:

key('variable-key', 'X')

当你有很多变量元素时,使用这种方法很有效。

注意:如果每个变量都有自己的范围(即,您有局部变量在文档的不同部分中不可见),则此方法无效。在这种情况下,应修改此方法。

问题2。

对于映射属性,您可以使用如下模板:

    <xsl:template match="@baseType[. = 'int']">
        <xsl:attribute name="baseType">
            <xsl:value-of select="'Long'" />
        </xsl:attribute>
    </xsl:template>

此转换的含义是:每次我们将baseType属性与int值匹配时,必须将其替换为Long值。

此转换将适用于文档中的每个@baseType属性。


使用所描述的策略,解决方案可以是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <!-- Index all variable elements in the document by name -->
    <xsl:key name="variable-key"
             match="//variable"
             use="@name" />

    <!-- Just for demo -->
    <xsl:template match="text()" />

    <!-- Identity template: copy attributes by default -->
    <xsl:template match="@*">
        <xsl:copy>
            <xsl:value-of select="." />
        </xsl:copy>
    </xsl:template>

    <!-- Match the structure type -->
    <xsl:template match="type[@baseType='structure']">
        <Item>
            <xsl:apply-templates select="*|@*" />
        </Item>
    </xsl:template>

    <!-- Match the variable instance -->
    <xsl:template match="variableInstance">
        <Field>
            <!-- Use the key to find the variable with the current name -->
            <xsl:apply-templates select="@*|key('variable-key', @name)/@baseType" />
        </Field>
    </xsl:template>

   <!-- Ignore attributes with baseType = 'structure' -->
    <xsl:template match="@baseType[. = 'structure']" />

    <!-- Change all baseType attributes with long values to an attribute
        with the same name but with an int value  -->
    <xsl:template match="@baseType[. = 'int']">
        <xsl:attribute name="baseType">
            <xsl:value-of select="'Long'" />
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

该代码将转换以下XML文档:

<!-- The code element is present just for demo -->
<code>
    <variable baseType="int" name="X" />
    <type baseType="structure" name="Y">
        <variableInstance name="X" />
    </type>
</code>

<Item name="Y">
    <Field baseType="Long" name="X"/>
</Item>

答案 1 :(得分:0)

Oki我得到了第1点xsltcake slicewith use of templates的解决方案。对于第二点,我可能会使用与Pablo Pozo在其答案中使用的模板类似的模板