XML / XSL notes

How to exclude given node from output XML tree?

Suppose we have an XML tree from which we need to exclude the node <ns:to-exclude>. That means the resulting tree should have all siblings and children of this node, but not the node itself.

<xsl:apply-templates select="ns:to-exclude/node()|*[not(self::ns:to-exclude)]" />

Why XML attributes declared as separate <xsd:element> entry should be used with explicit namespace prefix in XML?

XSD sample

<xsd:schema xmlns="http://foo/bar" targetNamespace="http://foo/bar" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:attribute name="id" type="xsd:positiveInteger" />
 
    <xsd:element name="customer">
        <xsd:complexType>
            <xsd:attribute ref="id" use="required" />
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

This XML does not validate:

Failing XML

<customer id="1" xmlns="http://foo/bar" />

Following XML samples validate fine:

Correct XML

<customer foo:id="1" xmlns="http://foo/bar" xmlns:foo="http://foo/bar" />

Another correct XML

<foo:customer foo:id="1" xmlns:foo="http://foo/bar" />

Because such XML attributes form separate (independent) namespace group "Global Attribute Partition", thus they don't match element namespace even if they are literally the same. Solution: either copy attribute declaration to each reference or use <xsd:elementGroup>:
<xsd:schema xmlns="http://foo/bar" targetNamespace="http://foo/bar" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:attribute name="id" type="xsd:positiveInteger" />
 
    <xsd:element name="customer">
        <xsd:complexType>
            <xsd:attributeGroup ref="id" />
        </xsd:complexType>
    </xsd:element>
 
    <xsd:attributeGroup name="id">
        <xsd:attribute name="id" use="required" />
    </xsd:attributeGroup>
</xsd:schema>

How to implement stylesheet that will generate another stylesheet?

The given XSL will generate another XSL as output.

All output XML elements need to be generated using <xsl:element> otherwise they cannot be separated from instructions of current XSL.

In order to generate extra namespaces, which are not explicitly used in resulting XML, we need to use a workaround described in Create xmlns attribute in the XML using XSLT Transformation, namely create a dummy node set and use extension to copy it's namespaces to current node.

It's handy to extra common logic into separate XSL and import it.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:extra="http://www.extra.org/exchange" version="1.0">
 
    <xsl:template match="text()|@*" />
 
    <xsl:variable name="dummy-node-set">
        <xsl:element name="extra:x" namespace="http://www.extra.org/exchange" />
    </xsl:variable>
 
    <xsl:template match="/">
        <xsl:element name="stylesheet">
            <xsl:attribute name="version">1.0</xsl:attribute>
            <xsl:copy-of select="ext:node-set($dummy-node-set)/*/namespace::*" />
 
            <!-- Some common/shared logic -->
            <xsl:element name="import">
                <xsl:attribute name="href">common.xsl</xsl:attribute>
            </xsl:element>
 
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>
 
    <xsl:template match="//extra:document/extra:number">
        <xsl:element name="template">
            <xsl:attribute name="match">//extra:document[<xsl:value-of select="../@index" />]/extra:number[text()='<xsl:value-of select="text()" />']</xsl:attribute>
 
            <xsl:element name="value-of">
                <xsl:attribute name="select">text()</xsl:attribute>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

programming/xml_xsl.txt · Last modified: 2010/10/27 13:11 by dmitry
 
 
Recent changes RSS feed Driven by DokuWiki