简体   繁体   中英

XSL add namespace definition to XML root only

I'd like to add a default namespace definition to the root element using XSL . Problem is however, that after XSL transformation, the subelement has attribute xmlns='' which I need to prevent.

XML Input:

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

Expected XML Output:

<?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>

I've tried with XSL like this:

<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> 

but result is:

<?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>

Any idea how to fix that?

Please note, there is a similar question: XSLT xmlns on root only , however in my case there are many more elements included (as just those listed in sample) in the XML, so it's not feasible for me.

change

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

to

<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>

Remember that with XSLT, you don't create namespace declarations. Rather, you create elements with the right expanded name (namespace URI plus local name), and the serializer looks after getting the namespace declarations right. So you want the changeSet element to be in namespace http://www.liquibase.org/xml/ns/dbchangelog , you have to create it in that namespace, you can't just put a default namespace declaration on its parent element. If you create the changeSet element in a different namespace from its parent, the serializer will add a namespace declaration to reflect your (apparent) intent.

Try it this way:

<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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM