简体   繁体   English

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

[英]Problems binding variable to node and referring to it in an XPath expression

I have following input: 我有以下输入:

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

and my desired output is 而我想要的输出是

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

For this purpose I am trying to find the xs:* (anything with W3C schema namespace) that has an attribute @name with the same value as the current element's @type attribute. 为此,我试图找到xs:*(具有W3C模式名称空间的任何东西),其属性@name与当前元素的@type属性具有相同的值。

However to "flatten" the xs:* element (which can of course be also written as element of some other type defined earlier in the document) I need to get this element into a variable and get through it the same templates as it is being now, recursively. 但是,要“展平” xs:*元素(当然也可以将其写为文档前面定义的某种其他类型的元素),我需要将该元素放入变量中并通过与模板相同的模板来进行访问现在,递归地。 For this purpose I want to call apply-templates select = "$var" . 为此,我想调用apply-templates select = "$var" But whenever I try to assign a variable with the element like this, the transformation fails because that variable is not set :( 但是每当我尝试使用这样的元素分配变量时,转换都会失败,因为未设置该变量:(

EDITED xslt begin 编辑的xslt开始

    <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 编辑的xslt结束

However when I check it with the real string, it works flawlessly... 但是,当我用真实的字符串检查它时,它可以正常工作...

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

I think the cause can be in the setting of the $type variable, however i have tried almost everything and nothing seems to be working, as I could not make an xpath based on variable :( 我认为原因可能在于$ type变量的设置,但是我几乎尝试了所有操作,但似乎没有任何效果,因为我无法基于变量进行xpath :(

I couldn't really understand what your XSLT was trying to do, so I approached it purely by comparing the input and output XML. 我真的无法理解您的XSLT想要做什么,因此我纯粹是通过比较输入和输出XML来实现的。

It looks like you want to look up simpleType and complexType elements by their name, so you can output them elsewhere in your XML. 看起来您想按其名称查找simpleTypecomplexType元素,因此可以将它们输出到XML的其他位置。 This is probably best achieved using a key 这可能是最好的使用钥匙

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

Then it is just a case of matching element elements which refer to one of these types 然后只是匹配element元素的情况,这些元素引用这些类型之一

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

(I am not really sure if you need to check the abc: prefix here too) (我不确定是否也需要在这里检查abc:前缀)

Then, to output details of the other type, you can just use the key 然后,要输出其他类型的详细信息,您只需使用键

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

Try this XSLT 试试这个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>

There are a number of problems with what you are doing, if we assume that we understand the task and the target vocabulary (XSD). 如果我们假设我们了解任务和目标词汇表(XSD),则您的操作会遇到很多问题。 For example, your expected output is not a valid schema because a local simpleType or complexType must not have a name attribute; 例如,您的预期输出不是有效的架构,因为本地的simpleType或complexType一定不能具有name属性; also the problems CMSp-McQ mentions: though this may not be a problem if you know that your input is using a limited subset of what XSD allows. CMSp-McQ提到的问题:尽管如果您知道您的输入使用的是XSD允许的有限子集,那么这可能不是问题。

However, treating this purely as a transformation of an arbitrary XML document, I'm having trouble seeing exactly what the problem is. 但是,仅将其视为任意XML文档的转换,就很难确切地知道问题所在。 You say "the transformation fails on that variable is not set", but that doesn't sound like a Saxon error message, it sounds like your paraphrase of an error message. 您说“在未设置该变量的情况下转换失败”,但这听起来不像是Saxon错误消息,听起来像是您对错误消息的解释。 You say that the variable test1 is unusable, but you don't show any code that is attempting to use it. 您说变量test1不可用,但没有显示任何试图使用它的代码。 It would be much easier to help you if you tell us exactly what you are doing and exactly what is going wrong, and preferably give us a complete (but minimal) source document and stylesheet so we can try it for ourselves. 如果您确切地告诉我们您在做什么和在哪里出了问题,这将很容易为您提供帮助,并且最好为我们提供完整(但最少)的源文档和样式表,以便我们自己尝试。

For the SO thought-police, I know this isn't an answer but it's too long to go in a comment. 对于SO思想警察,我知道这不是答案,但评论太久了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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