使用 XSLT 根据架构创建有效的 XML

发布于 2024-09-09 08:34:03 字数 8472 浏览 2 评论 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,换句话说:只有 attr1attr2 可以进入 bar,并且只有 attr3>attr4 可以放在 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)/*/*

哪个给了我我需要的额外位”的

I'm sorting a list of elements based on type, as defined in my schema. I know that XSLT can validate against a given schema, but what I want to do is check to make sure that my operation (a copy in this case) is valid before I do it.

Simplified code:

Incoming Data:

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

Desired Outgoing Data:

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

Somewhere in the Schema File:

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

(I'm just learning how to work with .xsd's, so to say it in words: only attr1 and attr2 can go in bar, and only attr3 and attr4 can go in stuff)

Basically, in the real situation there's too many tags to feasibly separate them manually. I'd like to know if there's a way to check the schema for whether the elements are right for whichever type they need to be sorted into. If they belong in one category, they should go to just that category.

All help is appreciated and thanks!

EDIT

@Alejandro's code works for the above basic pseudocode, but I'm having trouble implementing it in my files, which are more complex. For that reason, I'm adding a more complicated example:

Incoming Data

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

Desired Outgoing Data:

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

Somewhere in the Schema Files: (and somewhat more accurate than last time)

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

Finally, my xsl file

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

Thanks again for the help!

EDIT 2

So there's one minor change that I forgot to put in about my data file. Everything else should be the same except for the layout, which is nested like so:

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

What I'm trying to illustrate here is that within the groups are subcategories, and I need to match everything within those subcategories.

Alejandro, to make this worth your while (since you have been such an amazing help), you should put your response in a new answer, and when I try it and get it to work, I will up-vote and accept that answer.

Thanks again! You're really a lifesaver!

EDIT 3

I figured out the desired result. I changed the lines that said

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

to

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

Which gave me the extra bit that I needed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

终难遇 2024-09-16 08:34:03

架构(“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 可以做得更好。- 另外,如果架构是一种更合适的方法(元素定义和类型定义)此方法可以与键一起使用。另一种方法(输入驱动而不是模式驱动)尽管更复杂,但也可以完成,但我没有时间了。

编辑:现在,假设这些架构

schemaA.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>

schemaB.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>

schemaC.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>

Schema ("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>

Input:

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

Stylesheet:

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

Result:

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

Note: This is an XSLT 1.0 solution, but I think this can be done better with XSLT 2.0.- Also, if the schema is a more proper one (elements definitions and types definitions) this method could work with keys. Another method (input driven and not schema driven), despite being more complex, also could be done but I'm runnig out of time.

Edit: Now, suppose these schemas

schemaA.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>

schemaB.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>

schemaC.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>

This stylesheet:

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

Result:

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

Note: This works but your second questions (or problem) shows that there is no general case stylesheet. Why? Because with XSLT you must bind an input (with well known schema) to an output (with well known schema too). So this specific stylesheet could do the job:

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

Result:

<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>
回忆凄美了谁 2024-09-16 08:34:03

不确定您在这里寻找什么。无论您如何指示,XSLT 都会从源文档复制到目标文档。例如:

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

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

Not sure what you're looking for here. XSLT will copy from the source doc to the destination doc however you tell it to. For example:

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

What kind of validation are you looking for? You may be better off using something other than XSLT if you're looking for a more dynamic solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文