XSLT key matching with namespaces

I have a XSD document using namespaces, simplified to this:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
   xmlns:xns="urn:MyNs" targetNamespace="urn:MyNs">
  <xs:complexType name="Type1">
    <xs:sequence>
      <xs:element name="xxx" type="xs:short" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="Type2">
    <xs:sequence>
      <xs:element name="yyy" type="xs:short" />
      <xs:element name="value" type="xns:Type1" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="Type3">
    <xs:sequence>
      <xs:element name="yyy" type="xs:short" />
      <xs:element name="value" type="xns:Type2" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

I need to process the type dependencies in that file, for that I have the following XSL (again, simplified to minimal example):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text" encoding="utf-8" indent="yes"/>

    <xsl:param name="debug" select="no"/>

    <xsl:strip-space elements="*"/>

    <xsl:key name="type" match="xs:complexType" use="@name"/>

    <xsl:template match="*" mode="print-dependency">
        <xsl:value-of select="@name"/>
        <xsl:text>&#x0a;</xsl:text>
    </xsl:template>

    <xsl:template match="*" mode="process-type">
        <xsl:apply-templates mode="print-dependency"
                select="key('type', (
                    xs:attribute | xs:complexContent/xs:extension//xs:attribute |
                    xs:sequence/xs:element | xs:complexContent/xs:extension/xs:sequence/xs:element
                )/@type)"/>
    </xsl:template>

    <xsl:template match="/xs:schema">
        <xsl:apply-templates select="xs:complexType" mode="process-type">
            <xsl:with-param name="debug" select="$debug"/>
        </xsl:apply-templates>
    </xsl:template>

</xsl:stylesheet>

If I don't have the namespaces in the input XSD file (ie if I remove the "xns"), the output is as expected:

Type1
Type2

(Type1 is shown as dependency of Type 2 and Type2 as dependency of Type3)

However, with namespaces the output is empty, the type names are obviously not matching. Is it possible to manage that even when namespaces are used like in the example? (I don't know how to change the key() to match the complexType which uses the "targetNamespace" by default thus does not specify it explicitly in "name")


Ok, so to answer my own question based on the @michael's comment, I made it work by using this XSLT - removing the key() and using explicit matching instead, for both non-stripped and stripped strings:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text" encoding="utf-8" indent="yes"/>

    <xsl:param name="debug" select="no"/>

    <xsl:strip-space elements="*"/>

    <xsl:key name="type" match="xs:complexType" use="@name"/>

    <xsl:template match="*" mode="print-dependency">
        <xsl:value-of select="@name"/>
        <xsl:text>&#x0a;</xsl:text>
    </xsl:template>

    <xsl:template match="*" mode="process-dependency">
        <xsl:variable name="type" select="@type"/>
        <xsl:apply-templates mode="print-dependency"
                select="//xs:complexType[@name=$type]"/>
        <xsl:apply-templates mode="print-dependency"
                select="//xs:complexType[@name=substring-after($type, ':')]"/>
    </xsl:template>

    <xsl:template match="*" mode="process-type">
        <xsl:apply-templates mode="process-dependency"
                select="(
                    xs:attribute | xs:complexContent/xs:extension//xs:attribute |
                    xs:sequence/xs:element | xs:complexContent/xs:extension/xs:sequence/xs:element
                )"/>
    </xsl:template>

    <xsl:template match="/xs:schema">
        <xsl:apply-templates select="xs:complexType" mode="process-type">
            <xsl:with-param name="debug" select="$debug"/>
        </xsl:apply-templates>
    </xsl:template>

</xsl:stylesheet>

This then works for both namespaced and non-namespaced type names (or a mixture of those) exactly as I need. Optionally also two additional extra possibilities could be added if the type name could include namespace and be referred without the namespace.

链接地址: http://www.djcxy.com/p/34338.html

上一篇: XSD到FBS的XSLT转换(Flatbuffers)

下一篇: 与命名空间匹配的XSLT密钥