开发者

How to respect XML order with `<xsl:apply-template>` with XSLT?

开发者 https://www.devze.com 2023-04-12 19:28 出处:网络
I\'m working on a java code generation and the XSLT in which there are many of <xsl:if> or <xsl:choose> is not maintenable.

I'm working on a java code generation and the XSLT in which there are many of <xsl:if> or <xsl:choose> is not maintenable.

The field order is important for message, and the only way I've found to generate different field is to use switch case on different attribute.

This is an example XML data:

<?xml version="1.0" encoding="ISO-8859-1"?>
<message class="Message" length="28" id="0x12457836" 
                            package="org.goinfre.mail.data">
  <comment>bulk message</comment>
  <field name="state" type="short" size="2"/>
  <field name="reserve" size="2" reserved="true"/>
  <field name="reserve" size="1" reserved="true"/>
  <field name="identification" type="char">
    <array size="32" sizeName="IDENT_SIZE" encoding="UTF8" />
  </field>
  <field name="validity" type="int" size="4"/>
  <field name="voie" type="long" size="8"/>
</message>

The corresponding XSL is too long, but for example on each field I use an <xsl:choose> because the order of coding and decoding message's buffer is important. I need to use each field more than once.

<xsl:template match="/message">
  [...]
  <xsl:apply-templates select="field" mode="generateField"/><xsl:text>
  [...]
@Override
public byte[] toByteArray() {
    ByteBuffer buffer = ByteBuffer.allocate(LENGTH);
    super.toByteArray(buffer);
</xsl:text>
<xsl:apply-templates select="field" mode="generateBuffer"/>
    <xsl:text>
    return buffer.array();
}
</xsl:template>
<!--
*****************************************************************
** Generate a private field declaration.
**************************************************************-->
<xsl:template match="field" mode="generateField">
    <xsl:choose>
        <xsl:when test="array">
private int <xsl:value-of select="array/@sizeName"/><xsl:text> = </xsl:text><xsl:value-of select="array/@size"/>;
private <xsl:value-of select="@type"/><xsl:text>[] </xsl:text><xsl:value-of select="@name"/>
            <xsl:text> = new </xsl:text><xsl:value-of select="@type"/>
            <xsl:text>[</xsl:text><xsl:value-of select="array/@sizeName"/><xsl:text>];</xsl:text>
        </xsl:when>
        <xsl:when test="not(@reserved)">
private <xsl:value-of select="@type"/><xsl:text> </xsl:text><xsl:value-of select="@name"/>;
        </xsl:when>
    </xsl:choose>
</xsl:template>

I want to use different elements (field-array, field-reserved, field...) for each field, but the order is not respected.

Note: I can still change the format of the XML for now.


Create more specialized templates. Move the criteria from your conditional statements that are inside of the template up into the match criteria of the template(s).

Note: that multiple templates may match an element. If they have the same level of specificity in the match criteria, then they will get the same computed priority. You may have to specify @priority on the templates in order to "break the tie" and control which one should fire. In this instance, I added priority="1" to the template for field[array], to ensure that it matched instead of the one for field[not(@reserved)]`.

For instance:

<!--
*****************************************************************
** Generate a private field declaration 
    for fields that have array elements.
**************************************************************-->
<xsl:template match="field[array]" priority="1" mode="generateField">

private int <xsl:value-of select="array/@sizeName"/><xsl:text> = </xsl:text><xsl:value-of select="array/@size"/>;
private <xsl:value-of select="@type"/><xsl:text>[] </xsl:text><xsl:value-of select="@name"/>
            <xsl:text> = new </xsl:text><xsl:value-of select="@type"/>
            <xsl:text>[</xsl:text><xsl:value-of select="array/@sizeName"/><xsl:text>];</xsl:text>

</xsl:template>

<!--
*****************************************************************
** Generate a private field declaration
    for fields that do not have the attribute reserved.
**************************************************************-->
<xsl:template match="field[not(@reserved)]" mode="generateField">

private <xsl:value-of select="@type"/><xsl:text> </xsl:text><xsl:value-of select="@name"/>;

</xsl:template>

It may also improve performance, as the match criteria has an opportunity to be optimized by XSLT processors.

0

精彩评论

暂无评论...
验证码 换一张
取 消