将变量绑定到节点并在XPath表达式中引用它的问题

时间:2014-09-01 22:25:31

标签: xml xslt xpath xslt-2.0 saxon

我有以下输入:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:abc="http://abc.def"
        targetNamespace="http://abc.def"
        elementFormDefault="qualified" 
        attributeFormDefault="unqualified">
  <simpleType name="StatusCategoryId">
    <restriction base="string"/>
  </simpleType>
  <complexType name="StatusCategory">
    <sequence>
      <element name="statusCategoryId" 
               type="abc:StatusCategoryId"/>
      <element name="nameEN" type="string"/>
      <element name="nameCZ" type="string"/>
      <element name="claimCategoryId" type="string"/>
    </sequence>
  </complexType>
  <complexType name="StatusCategoryCollection">
    <sequence>
      <element name="statusCategoryInstance" 
               type="abc:StatusCategory" 
               minOccurs="0"
               maxOccurs="unbounded"/>
    </sequence>
  </complexType>
</schema>

我想要的输出是

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
        xmlns:abc="http://abc.def"
        targetNamespace="http://abc.def" 
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">
  <simpleType name="StatusCategoryId">
    <restriction base="string"/>
  </simpleType>
  <complexType name="StatusCategory">
    <sequence>
      <element name="statusCategoryId">
        <simpleType name="StatusCategoryId">
          <restriction base="string"/>
        </simpleType>
      </element>
      <element name="nameEN" type="string"/>
      <element name="nameCZ" type="string"/>
      <element name="claimCategoryId" type="string"/>
    </sequence>
  </complexType>
  <complexType name="StatusCategoryCollection">
    <sequence>
      <element name="statusCategoryInstance" 
               minOccurs="0" 
               maxOccurs="unbounded">
        <complexType name="StatusCategory">
          <sequence>
            <element name="statusCategoryId">
              <simpleType name="StatusCategoryId">
                <restriction base="string"/>
              </simpleType>
            </element>
            <element name="nameEN" type="string"/>
            <element name="nameCZ" type="string"/>
            <element name="claimCategoryId" type="string"/>
          </sequence>
        </complexType>
      </element>
    </sequence>
  </complexType>
</schema>

为此,我试图找到xs:*(具有W3C架构命名空间的任何东西),其属性@name具有与当前元素的@type属性相同的值。

然而,对于&#34;压扁&#34; xs:*元素(当然也可以写成文档中前面定义的其他类型的元素)我需要将这个元素放到一个变量中,然后通过递归方式获得与现在相同的模板。为此,我想打电话给apply-templates select = "$var"。但每当我尝试使用这样的元素分配变量时,转换就会失败,因为该变量未设置:(

EDITED xslt begin                  

    <xsl:variable name="test1">
        <xsl:copy-of select="root(.)//xs:*[@name= $type]"/>
    </xsl:variable>
    <!-- this variables above are here only out of context, 
         not real position in xslt code -->

<xsl:function name="pk:test">
  <xsl:param name="this"/>
  <xsl:variable name="test" select="in-scope-prefixes($this)"/>
  <xsl:element name="namespaces-root">
    <xsl:for-each select="$test">
      <xsl:element name="namespace">
        <xsl:element name="prefix">
          <xsl:value-of select="."/>
        </xsl:element>
        <xsl:element name="ns">
          <xsl:value-of 
            select="namespace-uri-for-prefix(.,$this)"/>
        </xsl:element>
      </xsl:element>
    </xsl:for-each>
  </xsl:element>
</xsl:function>

<xsl:function name="pk:childsHasType">
  <xsl:param name="this"/>
  <xsl:variable name="testX" 
                select="substring-before($this/@type,':')"/>
  <xsl:choose>
    <xsl:when test="$this/*">
      <xsl:for-each select="$this/*">
        <xsl:value-of select="concat(
          $testX != $var/namespace
                    [ns=$defaultSchemaNS]/prefix,
          string-join(pk:childsHasType(.),'|'))"/>
      </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of 
        select="$testX != $var/namespace
                          [ns=$defaultSchemaNS]/prefix"/>
    </xsl:otherwise>
  </xsl:choose>

</xsl:function>

<xsl:variable name="var" select="pk:test(./child::*[1])"/>
<xsl:variable name="defaultSchemaNS" 
              select="'http://www.w3.org/2001/XMLSchema'"/>

<xsl:template match="xs:element">
  <xsl:variable name="test0" 
                select="substring-before(@type,':')"/>
  <xsl:variable name="differentTypeTest" 
                select="string-join(pk:childsHasType(.), ', ')"/>
  <xsl:choose>
    <xsl:when test="contains($differentTypeTest,'true')">
      <xsl:variable name="type" select="xs:string" 
                    select="if (contains(@type, ':'))
                            then substring-after(@type,':')
                            else @type"/>
      <xsl:element name="element" 
                   namespace="{$var/namespace[prefix=$test]/ns}">
        <xsl:copy-of select="@*[name()!='type']"/>
        <xsl:text>&#10;</xsl:text>
        <!--next xsl copy to output works flawlessly-->
        <xsl:copy-of select="//node()[./@name = $type]"/>
        <!-- next variable here is unusable :( -->
        <xsl:variable name="test1">
          <xsl:copy-of select="root(.)//xs:*[@name= $type]"/>
        </xsl:variable>
        <xsl:text>&#10;</xsl:text>
        <xsl:apply-templates select="child::node()"/>
        <!--<xsl:copy-of select="child::*"/>-->
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="."/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

EDITED xslt end

然而,当我用真正的字符串检查它时,它可以完美地工作......

    <xsl:variable name="test2">
        <xsl:copy-of select="root(.)
                             //xs:*[@name= 'StatusCategoryId']"/>
    </xsl:variable>

我认为原因可能在于$ type变量的设置,但是我已经尝试了几乎所有东西,似乎没有任何工作,因为我无法根据变量创建一个xpath:(

2 个答案:

答案 0 :(得分:2)

我无法理解您的XSLT尝试做什么,所以我纯粹通过比较输入和输出XML来接近它。

看起来您希望按名称查找simpleTypecomplexType元素,因此您可以将它们输出到XML中的其他位置。这可能是使用密钥

最好的方法
<xsl:key name="complexType" match="xs:simpleType|xs:complexType" use="@name" />

然后只是匹配引用这些类型之一的element元素的情况

 <xsl:template match="xs:element[key('complexType', substring-after(@type, ':'))]">

(我不确定你是否也需要在这里查看abc:前缀)

然后,要输出其他类型的详细信息,您只需使用密钥

即可
<xsl:apply-templates select="key('complexType', substring-after(@type, ':'))" />

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
    <xsl:output method="xml" indent="yes" />

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

    <xsl:template match="xs:element[key('complexType', substring-after(@type, ':'))]">
        <xsl:copy>
            <xsl:apply-templates select="@*[local-name() != 'type']"/>
            <xsl:apply-templates select="key('complexType', substring-after(@type, ':'))" />
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>

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

答案 1 :(得分:1)

如果我们假设我们理解任务和目标词汇表(XSD),那么您正在做的事情有很多问题。例如,您的预期输出不是有效的模式,因为本地simpleType或complexType不能具有name属性;还有C.M.Sp-McQ提到的问题:如果你知道你的输入是使用XSD允许的有限子集,这可能不是问题。

然而,将其视为任意XML文档的转换,我很难确切地看到问题所在。你说&#34;转换失败,因为该变量未设置&#34;,但这听起来不像撒克逊错误消息,它听起来像是你的错误消息的释义。您说变量test1不可用,但您没有显示任何试图使用它的代码。如果你准确地告诉我们你在做什么以及到底出了什么问题,那么帮助你会更容易,最好给我们一个完整的(但是很少的)源文件和样式表,这样我们就可以自己试一试。

对于SO思想警察来说,我知道这不是一个答案,但是发表评论的时间太长了。