XSL仅将命名空间定义添加到XML根目录

时间:2014-02-25 08:02:09

标签: xml xslt xslt-1.0

我想使用XSL向根元素添加默认命名空间定义。但问题是,在XSL转换后,子元素具有我需要阻止的属性xmlns=''

XML输入:

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog>
      <changeSet author="abc" id="def">
...
    </changeSet>
</databaseChangeLog>

预期的XML输出:

<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
      <changeSet author="abc" id="def">
...
    </changeSet>
</databaseChangeLog>

我已尝试使用 XSL

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/databaseChangeLog">
        <databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
            xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
            <xsl:apply-templates select="node()|@*" />
        </databaseChangeLog>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}"> 
            <xsl:value-of select="." /> 
        </xsl:attribute>
    </xsl:template>

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

但结果是:

<?xml version="1.0" encoding="UTF-8"?><databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
      <changeSet xmlns="" author="abc" id="def">
...
    </changeSet>
</databaseChangeLog>

知道如何解决这个问题吗?

请注意,有一个类似的问题:XSLT xmlns on root only,但在我的情况下,XML中还包含更多元素(如示例中列出的那些元素),因此对我来说不可行。

3 个答案:

答案 0 :(得分:2)

变化

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

<xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="http://www.liquibase.org/xml/ns/dbchangelog">
        <xsl:apply-templates select="node()|@*" />
    </xsl:element>
</xsl:template>

答案 1 :(得分:2)

请记住,使用XSLT,您不会创建名称空间声明。相反,您使用正确的扩展名称(名称空间URI加本地名称)创建元素,并且序列化程序在获取正确的名称空间声明后进行查找。因此,您希望changeSet元素位于名称空间http://www.liquibase.org/xml/ns/dbchangelog中,您必须在该名称空间中创建它,您不能只在其父元素上放置默认名称空间声明。如果在与其父级不同的命名空间中创建changeSet元素,则序列化程序将添加名称空间声明以反映您的(明显)意图。

答案 2 :(得分:0)

以这种方式尝试:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/*">
    <databaseChangeLog 
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
        <xsl:apply-templates select="node()|@*" />
    </databaseChangeLog>
</xsl:template>

<xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="http://www.liquibase.org/xml/ns/dbchangelog"> 
        <xsl:apply-templates select="node()|@*" />
    </xsl:element>
</xsl:template>

<xsl:template match="@*">
    <xsl:attribute name="{local-name()}"> 
        <xsl:value-of select="." /> 
    </xsl:attribute>
</xsl:template>

<xsl:template match="text()|comment()|processing-instruction()" >
    <xsl:copy/>
</xsl:template>

</xsl:stylesheet>