这个问题让我头疼了很长一段时间。让我们来看看吧。
我正在处理的文件:
<?xml version="1.0" encoding="UTF-8"?>
<Message>
<Specification>
<!--1.-->
<Fruit>
<!--1.1-->
<Apple/>
<!--1.2-->
<Separator/>
<!--1.3-->
<Orange/>
<!--1.4-->
<SeperatorCLRF/>
</Fruit>
<!--2.-->
<Cookie>
<!--2.1-->
<Dough/>
<!--2.2-->
<Separator/>
<!--2.3-->
<Chocolate>
<!--2.3.1-->
<Crisp/>
<!--2.3.2-->
<Chunk/>
</Chocolate>
<!--2.4-->
<SeparatorCLRF/>
</Cookie>
</Specification>
<Repetitions>
<Repeat_1 begin="2.2 " end="2.3.2" amount="5"/>
<Repeat_2 begin="2.2 " end="2.4"/>
</Repetitions>
</Message>
我们的想法是将此XML转换为适当的XSD。子元素(例如1.x和1.x.x)将被赋予其自己的复杂类型并相应地引用。然而,重要的是在&#34;重复&#34;下找到的参考文献。找到并且也给出了他们自己的复杂类型,以便我能够告诉:&#34;这些元素可以重复无限次。&#34;或者&#34;这些元素可以重复这个次。&#34;
由于我刚刚开始编写XSL文件,以下代码段可能有点太长了,我道歉。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Message" type="Specification"/>
<xsl:apply-templates/>
</xs:schema>
</xsl:template>
<xsl:template match="Specification">
<xs:complexType name="Specification">
<xs:sequence>
<xsl:apply-templates select="//Specification/*" mode="references"/>
</xs:sequence>
</xs:complexType>
<xsl:apply-templates select="//Specification/*" mode="data"/>
<xsl:apply-templates select="//Specification/*" mode="subdata"/>
</xsl:template>
<xsl:template match="//Specification/*" mode="references">
<xs:element>
<xsl:attribute name="name" select="local-name()"/>
<xsl:attribute name="type" select="local-name()"/>
</xs:element>
</xsl:template>
<xsl:template match="//Specification/*" mode="data">
<xs:complexType name="{local-name()}">
<xs:sequence>
<xsl:for-each select="*">
<xs:element>
<xsl:attribute name="name" select="local-name()"/>
<xsl:choose>
<xsl:when test="*">
<xsl:attribute name="type"
select="concat(name(..),'_', local-name())"/>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="type">xs:string</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xs:element>
</xsl:for-each>
</xs:sequence>
</xs:complexType>
</xsl:template>
<xsl:template match="//Specification/*" mode="subdata">
<xsl:variable name="current_name" select="local-name()"/>
<xsl:for-each select="*">
<xsl:if test="*">
<xs:complexType>
<xsl:attribute name="name" select="concat($current_name,'_', local-name())"/>
<xs:sequence>
<xsl:for-each select="*">
<xs:element>
<xsl:attribute name="name" select="local-name()"/>
<xsl:attribute name="type">xs:string</xsl:attribute>
</xs:element>
</xsl:for-each>
</xs:sequence>
</xs:complexType>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
结果如下XSD:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Message" type="Specification"/>
<xs:complexType name="Specification">
<xs:sequence>
<xs:element name="Fruit" type="Fruit"/>
<xs:element name="Cookie" type="Cookie"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Fruit">
<xs:sequence>
<xs:element name="Apple" type="xs:string"/>
<xs:element name="Separator" type="xs:string"/>
<xs:element name="Orange" type="xs:string"/>
<xs:element name="SeperatorCLRF" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Cookie">
<xs:sequence>
<xs:element name="Dough" type="xs:string"/>
<xs:element name="Separator" type="xs:string"/>
<xs:element name="Chocolate" type="Cookie_Chocolate"/>
<xs:element name="SeparatorCLRF" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Cookie_Chocolate">
<xs:sequence>
<xs:element name="Crisp" type="xs:string"/>
<xs:element name="Chunk" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
几点说明:
begin
和end
将始终正确排序。换句话说,end
中的引用将始终位于begin
中的引用之后。 如您所见,XSD尚未包含重复内容。目的是得到这个:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Message" type="Specification"/>
<xs:complexType name="Specification">
<xs:sequence>
<xs:element name="Fruit" type="Fruit"/>
<xs:element name="Cookie" type="Cookie"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Fruit">
<xs:sequence>
<xs:element name="Apple" type="xs:string"/>
<xs:element name="Separator" type="xs:string"/>
<xs:element name="Orange" type="xs:string"/>
<xs:element name="SeperatorCLRF" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Cookie">
<xs:sequence>
<xs:element name="Dough" type="xs:string"/>
<xs:element name="Repeat_2" type="Repeat_2" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Cookie_Chocolate">
<xs:sequence>
<xs:element name="Crisp" type="xs:string"/>
<xs:element name="Chunk" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Repeat_2">
<xs:sequence>
<xs:element name="Repeat_1" type="Repeat_1" maxOccurs="5"/>
<xs:element name="SeparatorCLRF" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Repeat_1">
<xs:sequence>
<xs:element name="Separator" type="xs:string"/>
<xs:element name="Chocolate" type="Cookie_Chocolate"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
我必须解决问题的想法如下:在逐步通过节点时,不断检查是否可以在重复中找到当前节点。如果找到begin
属性,请通过使用起始标记开始包装元素。然后在找到end
属性后,关闭标记。
类似的东西:
<xsl:variable name="currentNode" select="preceding-sibling::comment()[1]"/>
<xsl:for-each select="//Repetitions/Repeat">
<xsl:choose>
<xsl:if test="$currentNode = @begin">
<complexType>
</xsl:if>
<xsl:if test="$currentNode = @end">
</complexType>
</xsl:if>
</xsl:choose>
</xsl:for-each>
上面的示例应该说明我尝试使用起始和结束标记。显然这不起作用,因为你必须在if语句中终止标记。
我想,最大的问题是包装重复元素&#34;有点破坏了XSLT的其余部分。啊!
我完全陷入了这一点,因为我一直在想要开始一个标签然后结束标签的问题上磕磕绊绊。这对我来说是唯一合乎逻辑的东西,但这是不可能做到的。也许这纯粹是通过使用XSLT来解决的。
希望有人能把我送到正确的方向!无论如何,谢谢你的阅读。
EDIT1:我应该可以在XML文件中添加一些额外的数据。可能更容易获得我想要的结果的东西。如果有人读到这篇文章可能知道最好添加什么,请发表评论。
EDIT2:我开始认为这个问题无法用当前的结构来解决。我尝试在初始XML结构中添加元素,但我一直发现自己陷入了一个问题:实际上包装了重复的块。如果我创建所有complexTypes(就像我在XSLT中所做的那样)之前确定重复块,则无法正确包装,因为重复块的一部分可能必须以complexType结尾#39;已经制作好了。即使我决定先确定重复块,我也会遇到同样的问题。
真的希望从人们那里得到一些指示或想法。