XSLT:意外的继承null xmlns属性

时间:2013-03-13 13:14:32

标签: xml xslt xslt-2.0

我正在编写一个转换,我希望将xmlns属性(xmlns="myNS")添加到根节点。

应用转换时,xmlns属性包含在某些子元素中。

我无法弄清楚如何将我的转换更改为仅将其应用于根元素。

XML

<db:result xmlns:db="http://www.sonicsw.com/esb/service/dbservice">
    <db:resultSet version="1.1">
        <db:row>
            <id>a</id>
            <value1>b</value1>
            <value2>c</value2>
        </db:row>
        <db:row>
            <id>a</id>
            <value1>d</value1>
            <value2>e</value2>
        </db:row>
        <db:row>
            <id>a</id>
            <value1>f</value1>
            <value2>g</value2>
        </db:row>
        <db:row>
            <id>a</id>
            <value1>h</value1>
            <value2>i</value2>
        </db:row>
    </db:resultSet>
</db:result>

XSLT

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:db="http://www.sonicsw.com/esb/service/dbservice" 
    exclude-result-prefixes="db">
    <xsl:template match="/">
            <xsl:for-each-group select="//db:row" group-by="id">
                <xsl:sort select="id"/>
                    <xsl:apply-templates select="." mode="document"/>
            </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="db:row" mode="document">
        <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="myNS">
            <id><xsl:value-of select="id"/></id>
            <lines>
                <xsl:apply-templates select="//db:row[id=current()/id]" mode="line"/>
            </lines>
        </root>        
    </xsl:template>

    <xsl:template match="db:row" mode="line">
        <line>
            <valueof1><xsl:value-of select="value1"/></valueof1>
            <valueof2><xsl:value-of select="value2"/></valueof2>
        </line>
    </xsl:template>
</xsl:stylesheet>

XML输出

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="myNS">
    <id>a</id>
    <lines>
        <line xmlns="">
            <valueof1>b</valueof1>
            <valueof2>c</valueof2>
        </line>
        <line xmlns="">
            <valueof1>d</valueof1>
            <valueof2>e</valueof2>
        </line>
        <line xmlns="">
            <valueof1>f</valueof1>
            <valueof2>g</valueof2>
        </line>
        <line xmlns="">
            <valueof1>h</valueof1>
            <valueof2>i</valueof2>
        </line>
    </lines>
</root>

XML预期输出

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="myNS">
    <id>a</id>
    <lines>
        <line>
            <valueof1>b</valueof1>
            <valueof2>c</valueof2>
        </line>
        <line>
            <valueof1>d</valueof1>
            <valueof2>e</valueof2>
        </line>
        <line>
            <valueof1>f</valueof1>
            <valueof2>g</valueof2>
        </line>
        <line>
            <valueof1>h</valueof1>
            <valueof2>i</valueof2>
        </line>
    </lines>
</root>

注意:我找到了这个现有帖子,但无法解决如何应用建议的解决方案:

1 个答案:

答案 0 :(得分:2)

样式表中的文字结果元素从样式表中的范围内的xmlns声明中获取其名称空间,即在

    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="myNS">
        <id><xsl:value-of select="id"/></id>
        <lines>
            <xsl:apply-templates select="//db:row[id=current()/id]" mode="line"/>
        </lines>
    </root>

root元素及其所有未加前缀的子元素都在myNS命名空间中。但是在

<xsl:template match="db:row" mode="line">
    <line>
        <valueof1><xsl:value-of select="value1"/></valueof1>
        <valueof2><xsl:value-of select="value2"/></valueof2>
    </line>
</xsl:template>

linevalueofN元素没有名称空间,因为样式表中此时范围内没有默认xmlns

所以简单的答案是将xmlns="myNS"root模板中的db:row元素移到顶层xsl:stylesheet而不是:

<xsl:stylesheet version="2.0" 
    xmlns="myNS"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:db="http://www.sonicsw.com/esb/service/dbservice" 
    exclude-result-prefixes="db">
    <xsl:template match="/">
            <xsl:for-each-group select="//db:row" group-by="id">
                <xsl:sort select="id"/>
                    <xsl:apply-templates select="." mode="document"/>
            </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="db:row" mode="document">
        <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <id><xsl:value-of select="id"/></id>
            <lines>
                <xsl:apply-templates select="//db:row[id=current()/id]" mode="line"/>
            </lines>
        </root>        
    </xsl:template>

    <xsl:template match="db:row" mode="line">
        <line>
            <valueof1><xsl:value-of select="value1"/></valueof1>
            <valueof2><xsl:value-of select="value2"/></valueof2>
        </line>
    </xsl:template>
</xsl:stylesheet>

虽然请注意,如果原始XML中的row元素不具有相同的ID,则此样式表将不会生成格式正确的输出,因为您将获得多个root元素单身父母。您可能希望在match="/"模板中添加包装元素,以确保输出格式正确。

P.S。由于您使用的是for-each-group,因此丢失mode="document"模板并将其内容直接移到feg中可能会更有效,然后使用current-group而不必过滤{{1} }}:

[id=current()/id]