0

我正在根据我的架构中定义的类型对元素列表进行排序。我知道 XSLT 可以针对给定的模式进行验证,但我想做的是在执行之前检查以确保我的操作(在这种情况下为副本)是有效的。

简化代码:

传入数据:

<?xml version="1.0"?>
<sch:foo xmlns:sch="http://www.whatever.com/schema">
    <sch:attr1>val1</sch:attr1>
    <sch:attr2>val2</sch:attr2>
    <sch:attr3>val3</sch:attr3>
    <sch:attr4>val4</sch:attr4>
</sch:foo>

所需的传出数据:

<?xml version="1.0"?>
<sch:fooOut xmlns:sch="http://www.whatever.com/schema">
    <sch:bar>
        <sch:attr1>val1</sch:attr1>
        <sch:attr2>val2</sch:attr2>
    </sch:bar>
    <sch:stuff>
        <sch:attr3>val3</sch:attr3>
        <sch:attr4>val4</sch:attr4>
    </sch:stuff>
</sch:fooOut>

架构文件中的某处:

<complexType name="fooOut">
    <sequence>
        <!-- ... -->
        <element name="bar">
            <complexType>
                <sequence>
                    <element name="attr1" type="sch:myBarType" minOccurs="0" maxOccurs="unbounded"/>
                    <element name="attr2" type="sch:myBarType" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
            </complexType>
        </element>
        <element name="stuff">
            <complexType>
                <sequence>
                    <element name="attr3" type="sch:myStuffType" minOccurs="0" maxOccurs="unbounded"/>
                    <element name="attr4" type="sch:myStuffType" minOccurs="0" maxOccurs="unbounded"/>
                </sequence>
            </complexType>
        </element>
    </sequence>
</complexType>

(我只是在学习如何使用 .xsd,所以用语言来表达:only attr1and attr2can go in bar, and only attr3and attr4can go in stuff

基本上,在实际情况下,标签太多,无法手动将它们分开。我想知道是否有办法检查架构中的元素是否适合需要分类的任何类型。如果他们属于一个类别,他们应该只属于那个类别。

感谢所有帮助,谢谢!

编辑

@Alejandro 的代码适用于上述基本伪代码,但我无法在我的文件中实现它,这些文件更复杂。出于这个原因,我添加了一个更复杂的示例:

传入数据

<?xml version="1.0"?>
<sch:foo xmlns:sch="http://www.whatever.com/schema">
    <sch:nesting>
        <sch:myGroup>
            <sch:mustHaveData>asdf</sch:mustHaveData>

            <sch:attr1>val1</sch:attr1>
            <sch:attr2>val2</sch:attr2>
            <sch:attr3>val3</sch:attr3>
            <sch:attr4>val4</sch:attr4>
        </sch:myGroup>
        <sch:myGroup>
            <sch:mustHaveData>asdf2</sch:mustHaveData>

            <sch:attr1>val5</sch:attr1>
            <sch:attr2>val6</sch:attr2>
            <sch:attr3>val7</sch:attr3>
            <sch:attr4>val8</sch:attr4>
        </sch:myGroup>
    </sch:nesting>
</sch:foo>

所需的传出数据:

<?xml version="1.0"?>
<sch:fooOut xmlns:sch="http://www.whatever.com/schema">
    <sch:anotherGroup>
        <sch:name>foobar</sch:name>
        <sch:bar>
            <sch:attr1>val1</sch:attr1>
            <sch:attr2>val2</sch:attr2>
        </sch:bar>
        <sch:stuff>
            <sch:attr3>val3</sch:attr3>
            <sch:attr4>val4</sch:attr4>
        </sch:stuff>
    </sch:anotherGroup>
    <sch:anotherGroup>
        <sch:name>foobar</sch:name>
        <sch:bar>
            <sch:attr1>val5</sch:attr1>
            <sch:attr2>val6</sch:attr2>
        </sch:bar>
        <sch:stuff>
            <sch:attr3>val7</sch:attr3>
            <sch:attr4>val8</sch:attr4>
        </sch:stuff>
    </sch:anotherGroup>
</sch:fooOut>

架构文件中的某处:(并且比上次更准确)

<complexType name="anotherGroup">
    <sequence>
        <element name="name" type="xs:string" minOccurs="1" maxOccurs="1" />
        <element name="bar" type="barListType" minOccurs="0" maxOccurs="1" />
        <element name="stuff" type="stuffListType" minOccurs="0" maxOccurs="1" />
    </sequence>
</complexType>

<!-- in another .xsd -->
<complexType name="barListType">
    <group ref="barGroup" maxOccurs="unbounded" />
</complexType>

<complexType name="stuffListType">
    <group ref="stuffGroup" maxOccurs="unbounded" />
</complexType>

<!-- in yet another .xsd -->
<group name="barGroup">
    <choice>
        <element name="attr1" type="blah1" minOccurs="0" maxOccurs="1" />
        <element name="attr2" type="blah2" minOccurs="0" maxOccurs="1" />
        <!-- etc -->
    </choice>
</group>

<group name ="stuffGroup">
    <choice>
        <element name="attr3" type="blah3" minOccurs="0" maxOccurs="1" />
        <element name="attr4" type="blah4" minOccurs="0" maxOccurs="1" />
        <!-- etc -->
    </choice>
</group>

最后,我的 xsl 文件

    <xsl:output method="xml" encoding="UTF-8" />

    <xsl:param name="schema-name" select="'myXsd.xsd'" />
    <xsl:template match="/">
        <xsl:apply-templates select="document($schema-name)/xs:complexType[@*]" />
        <xsl:apply-templates select="sch:nesting"/>
    </xsl:template>

    <xsl:template match="sch:nesting/xs:element[xs:complexType]">
        <xsl:element name="{@name}" namespace="http://www.whatever.com/schema">
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

    <xsl:template match="sch:nesting/xs:element[not(xs:complexType)]">
        <xsl:element name="{@name}" namespace="http://www.whatever.com/schema">
            <xsl:value-of select="/*/sch:*[name()=current()/@name or
                                  substring-after(name(),':')=current()/@name]"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="sch:nesting">
        <xsl:element name="anotherGroup">
            <xsl:element name="name">
                <!-- Whatever -->
            </xsl:element>

            <xsl:apply-templates /> <!-- I want to drop the data here, but this is definitely wrong -->

        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

再次感谢您的帮助!

编辑 2

因此,我忘记对我的数据文件进行一项小的更改。除了布局,其他一切都应该是相同的,它是这样嵌套的:

<?xml version="1.0"?>
<sch:foo xmlns:sch="http://www.whatever.com/schema">
    <sch:nesting>
        <sch:myGroup>
            <inner1>
                <sch:mustHaveData>asdf</sch:mustHaveData>

                <sch:attr1>val1</sch:attr1>
            </inner1>
            <inner2>
                <sch:attr2>val2</sch:attr2>
                <sch:attr3>val3</sch:attr3>
                <sch:attr4>val4</sch:attr4>
            </inner2>
        </sch:myGroup>
        <sch:myGroup>
            <inner1>
                <sch:mustHaveData>asdf2</sch:mustHaveData>

                <sch:attr1>val5</sch:attr1>
            </inner1>
            <inner2>
                <sch:attr2>val6</sch:attr2>
                <sch:attr3>val7</sch:attr3>
                <sch:attr4>val8</sch:attr4>
            </inner2>
        </sch:myGroup>
    </sch:nesting>
</sch:foo>

我在这里试图说明的是,组中有子类别,我需要匹配这些子类别中的所有内容。

亚历杭德罗,为了让这个值得你花时间(因为你一直是一个了不起的帮助),你应该把你的回应放在一个新的答案中,当我尝试它并让它发挥作用时,我会投票并接受这个答案。

再次感谢!你真的是救命恩人!

编辑 3

我想出了想要的结果。我改变了说

<xsl:copy-of select="*[local-name()=document($schema-name)/*/*

<xsl:copy-of select="*/*[local-name()=document($schema-name)/*/*

这给了我所需的额外部分。

4

2 回答 2

3

架构(“schema.xs”):

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema">
    <element name="fooOut">
        <complexType name="fooOut">
            <sequence>
                <element name="bar">
                    <complexType>
                        <sequence>
                            <element name="attr1" type="sch:myBarType" minOccurs="0" maxOccurs="unbounded"/>
                            <element name="attr2" type="sch:myBarType" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
                    </complexType>
                </element>
                <element name="stuff">
                    <complexType>
                        <sequence>
                            <element name="attr3" type="sch:myStuffType" minOccurs="0" maxOccurs="unbounded"/>
                            <element name="attr4" type="sch:myStuffType" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>

输入:

<sch:foo xmlns:sch="http://www.whatever.com/schema">   
    <sch:attr1>val1</sch:attr1>   
    <sch:attr2>val2</sch:attr2>   
    <sch:attr3>val3</sch:attr3>   
    <sch:attr4>val4</sch:attr4>   
</sch:foo> 

样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:sch="http://www.whatever.com/schema">
    <xsl:param name="schema-name" select="'schema.xs'"/>
    <xsl:variable name="input" select="/"/>
    <xsl:template match="/">
        <xsl:apply-templates select="document($schema-name)/node()"/>
    </xsl:template>
    <xsl:template match="xs:element[xs:complexType]">
        <xsl:element name="{@name}" namespace="http://www.whatever.com/schema">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="xs:element[not(xs:complexType)]">
        <xsl:element name="{@name}" namespace="http://www.whatever.com/schema">
            <xsl:value-of select="$input/*/sch:*[name()=current()/@name or
                                        substring-after(name(),':')=current()/@name]"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

结果:

<?xml version="1.0" encoding="UTF-16"?>
<fooOut xmlns="http://www.whatever.com/schema">
    <bar>
        <attr1>val1</attr1>
        <attr2>val2</attr2>
    </bar>
    <stuff>
        <attr3>val3</attr3>
        <attr4>val4</attr4>
    </stuff>
</fooOut>

注意:这是一个 XSLT 1.0 解决方案,但我认为使用 XSLT 2.0 可以做得更好。另外,如果模式是更合适的模式(元素定义和类型定义),此方法可以使用键。另一种方法(输入驱动而不是模式驱动)尽管更复杂,但也可以完成,但我的时间不多了。

编辑:现在,假设这些模式

架构A.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema">
    <include schemaLocation="schemaB.xsd"/>
    <element name="fooOut" type="fooOut"/>
    <complexType name="fooOut">
        <element name="anotherGroup" type="anotherGroup" minOccurs="0" maxOccurs="unbounded"/>
    </complexType>
    <complexType name="anotherGroup">
        <sequence>
            <element name="name" type="xs:string" minOccurs="1" maxOccurs="1" />
            <element name="bar" type="barListType" minOccurs="0" maxOccurs="1" />
            <element name="stuff" type="stuffListType" minOccurs="0" maxOccurs="1" />
        </sequence>
    </complexType>
</schema>

架构B.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema">
    <include schemaLocation="schemaC.xsd"/>
    <complexType name="barListType">
        <group ref="barGroup" maxOccurs="unbounded" />
    </complexType>
    <complexType name="stuffListType">
        <group ref="stuffGroup" maxOccurs="unbounded" />
    </complexType>
</schema>

架构C.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema">
    <group name="barGroup">
        <choice>
            <element name="attr1" type="blah1" minOccurs="0" maxOccurs="1" />
            <element name="attr2" type="blah2" minOccurs="0" maxOccurs="1" />
            <!-- etc -->
        </choice>
    </group>
    <group name ="stuffGroup">
        <choice>
            <element name="attr3" type="blah3" minOccurs="0" maxOccurs="1" />
            <element name="attr4" type="blah4" minOccurs="0" maxOccurs="1" />
            <!-- etc -->
        </choice>
    </group>
</schema>

这个样式表:

<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="xml" encoding="UTF-8" />
    <xsl:param name="schema-name" select="'schemaA.xsd'" />
    <xsl:variable name="input" select="/*/*/*" />
    <xsl:variable name="root" select="document($schema-name)/*/xs:element[not(..//xs:element/@ref = @name)]" />
    <xsl:variable name="uri" select="$root/../@targetNamespace" />
    <xsl:template match="/" name="root">
        <xsl:param name="schema" select="$root/../*"/>
        <xsl:choose>
            <xsl:when test="$schema[self::xs:include]">
                <xsl:call-template name="root">
                    <xsl:with-param name="schema" select="$schema[not(self::xs:include)]|document($schema[self::xs:include]/@schemaLocation)/*/*"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="$root">
                    <xsl:with-param name="schema" select="$schema"/>
                    <xsl:with-param name="input" select="$input"/>
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="xs:element">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:variable name="complex" select="xs:complexType|
                                             $schema[self::xs:complexType][@name=current()/@type]"/>
        <xsl:element name="{@name|@ref}" namespace="{$uri}">
            <xsl:choose>
                <xsl:when test="$complex">
                    <xsl:apply-templates select="$complex">
                        <xsl:with-param name="schema" select="$schema"/>
                        <xsl:with-param name="input" select="$input"/>
                    </xsl:apply-templates>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$input[local-name()=current()/@name and
                                  namespace-uri()=$uri]"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
    <xsl:template match="xs:group[@ref]">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:apply-templates select="$schema[self::xs:group][@name=current()/@ref]">
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="input" select="$input"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="xs:element[@name='name']" priority="1">
        <xsl:element name="{@name}" namespace="{$uri}">foobar</xsl:element>
    </xsl:template>
    <xsl:template match="xs:element[@maxOccurs='unbounded']">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:variable name="current" select="."/>
        <xsl:for-each select="$input">
            <xsl:element name="{$current/@name}" namespace="{$uri}">
                <xsl:apply-templates select="$schema[self::xs:complexType][@name=$current/@type]">
                    <xsl:with-param name="schema" select="$schema"/>
                    <xsl:with-param name="input" select="./*"/>
                </xsl:apply-templates>
            </xsl:element>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="*">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:apply-templates>
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="input" select="$input"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

结果:

<fooOut xmlns="http://www.whatever.com/schema">
    <anotherGroup>
        <name>foobar</name>
        <bar>
            <attr1>val1</attr1>
            <attr2>val2</attr2>
        </bar>
        <stuff>
            <attr3>val3</attr3>
            <attr4>val4</attr4>
        </stuff>
    </anotherGroup>
    <anotherGroup>
        <name>foobar</name>
        <bar>
            <attr1>val5</attr1>
            <attr2>val6</attr2>
        </bar>
        <stuff>
            <attr3>val7</attr3>
            <attr4>val8</attr4>
        </stuff>
    </anotherGroup>
</fooOut>

注意:这可行,但您的第二个问题(或问题)表明没有通用案例样式表。为什么?因为使用 XSLT,您必须将输入(具有众所周知的模式)绑定到输出(也具有众所周知的模式)。所以这个特定的样式表可以完成这项工作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sch="http://www.whatever.com/schema">
    <xsl:output method="xml" encoding="UTF-8" />
    <xsl:param name="schema-name" select="'schemaC.xsd'" />
    <xsl:template match="sch:foo">
        <sch:fooOut>
            <xsl:apply-templates/>
        </sch:fooOut>
    </xsl:template>
    <xsl:template match="sch:myGroup">
        <sch:anotherGroup>
            <sch:name>foobar</sch:name>
            <sch:bar>
                <xsl:copy-of select="*[local-name()=document($schema-name)/*/*[@name='barGroup']//@name]" />
            </sch:bar>
            <sch:stuff>
                <xsl:copy-of select="*[local-name()=document($schema-name)/*/*[@name='stuffGroup']//@name]" />
            </sch:stuff>
        </sch:anotherGroup>
    </xsl:template>
</xsl:stylesheet>

结果:

<sch:fooOut xmlns:sch="http://www.whatever.com/schema">
    <sch:anotherGroup>
        <sch:name>foobar</sch:name>
        <sch:bar>
            <sch:attr1>val1</sch:attr1>
            <sch:attr2>val2</sch:attr2>
        </sch:bar>
        <sch:stuff>
            <sch:attr3>val3</sch:attr3>
            <sch:attr4>val4</sch:attr4>
        </sch:stuff>
    </sch:anotherGroup>
    <sch:anotherGroup>
        <sch:name>foobar</sch:name>
        <sch:bar>
            <sch:attr1>val5</sch:attr1>
            <sch:attr2>val6</sch:attr2>
        </sch:bar>
        <sch:stuff>
            <sch:attr3>val7</sch:attr3>
            <sch:attr4>val8</sch:attr4>
        </sch:stuff>
    </sch:anotherGroup>
</sch:fooOut>
于 2010-07-08T22:36:58.087 回答
0

不知道你在这里找什么。XSLT 将从源文档复制到目标文档,但您告诉它。例如:

<sch:fooOut>
  <sch:bar>
    <xsl:copy>
      <sch1:attr1>
      <sch1:attr2>
    </xsl:copy>
  </sch:bar>
</sch:fooOut>

您在寻找什么样的验证?如果您正在寻找更动态的解决方案,那么使用 XSLT 以外的其他东西可能会更好。

于 2010-07-08T19:26:22.273 回答