跨嵌套元素的 XSLT 重复数据删除
XSLT Deduplicate across nested elements
我有 XSD 架构,我将其用作生成 XSLT 的源,该 XSLT 根据架构重新排序 XML 文件中的元素(基本上,使用 XSLT 从 XSD).我需要删除 XSD.
中 xs:choice 元素(也可以嵌套)中多次出现的元素
我的 XML 有很多可选字段,所以我使用 choice 将它们分组,因为它们中的一些一起出现。选择是问题的根源,因为某些元素在选择元素内部重复并冒泡到生成的 XSLT 模板。
编辑: 我试图通过将 complexType 保存在一个变量中来使用多次传递。但是我不知道如何在特定的命名空间上进行身份转换。
XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://test.example.com/xsd" elementFormDefault="qualified">
<xs:element name="__Schema">
<xs:complexType>
<xs:choice>
<xs:element ref="ref"/>
<xs:sequence>
<xs:element ref="schema"/>
<xs:element minOccurs="0" ref="type"/>
<xs:element minOccurs="0" ref="description"/>
<xs:choice>
<xs:element ref="allOf"/>
<xs:element ref="__Property"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:element ref="type"/>
<xs:element ref="__Items"/>
</xs:sequence>
<xs:choice>
<xs:element ref="pattern"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="enum"/>
</xs:choice>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="description" type="xs:string"/>
<xs:element name="schema" type="xs:NCName"/>
<xs:element name="ref" type="xs:string"/>
<xs:element name="allOf" substitutionGroup="oneOf"/>
<xs:element name="type" type="xs:string"/>
<xs:element name="__Property" type="xs:string"/>
<xs:element name="enum" type="xs:string"/>
<xs:element name="__Items" type="xs:string"/>
<xs:element name="oneOf" type="xs:string"/>
<xs:element name="pattern" type="xs:string"/>
</xs:schema>
我的模板:
<?xml version="1.0" encoding="UTF-8"?>
<xslt:stylesheet version="2.0"
xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xt="http://www.w3.org/1999/XSL/TransformAlias">
<xslt:output method="xml" indent="yes"/>
<xslt:namespace-alias stylesheet-prefix="xt" result-prefix="xslt" />
<xslt:template match="*[@name and @substitutionGroup]"/>
<xslt:template match="xs:element[@name and not(@substitutionGroup) and not(@group)]">
<xslt:element name="xslt:template">
<xslt:attribute name="match">
<xslt:value-of select="string-join(@name|../xs:element[@substitutionGroup=current()/@name]/@name, '|')"/>
</xslt:attribute>
<xslt:apply-templates select="*"/>
</xslt:element>
</xslt:template>
<xslt:template match="xs:element[@ref]">
<xslt:element name="xslt:apply-templates">
<xslt:attribute name="select">
<xslt:value-of select="@ref"/>
</xslt:attribute>
</xslt:element>
</xslt:template>
<xslt:template match="xs:group[@ref]">
<xslt:apply-templates select="//*[@name=current()/@ref]/*"/>
</xslt:template>
<xslt:template match="xs:group[@name]"/>
<xslt:template match="xs:choice|xs:sequence|xs:complexType">
<xslt:apply-templates select="*"/>
</xslt:template>
<xslt:template match="xs:schema">
<xt:stylesheet version="2.0">
<xt:output method="text" indent="no"/>
<xslt:apply-templates select="*"/>
</xt:stylesheet>
</xslt:template>
</xslt:stylesheet>
目前,结果如下:
<xslt:template match="__Schema">
<xslt:apply-templates select="ref"/>
<xslt:apply-templates select="schema"/>
<xslt:apply-templates select="type"/>
<xslt:apply-templates select="description"/>
<xslt:apply-templates select="allOf"/>
<xslt:apply-templates select="__Property"/>
<xslt:apply-templates select="type"/>
<xslt:apply-templates select="__Items"/>
<xslt:apply-templates select="pattern"/>
<xslt:apply-templates select="enum"/>
</xslt:template>
我需要第二个 select="type"
消失,同时保留所有其他元素的顺序。我不想创建管道。
对于该示例,如果您添加
<xslt:key name="choice-ref" match="xs:choice//xs:element[@ref]" use="@ref"/>
<xslt:template match="xs:choice//xs:element[@ref][not(. is key('choice-ref', @ref, ancestor::xs:choice[1])[1])]" priority="10"/>
你得到
<xslt:template match="__Schema">
<xslt:apply-templates select="ref"/>
<xslt:apply-templates select="schema"/>
<xslt:apply-templates select="type"/>
<xslt:apply-templates select="description"/>
<xslt:apply-templates select="allOf"/>
<xslt:apply-templates select="__Property"/>
<xslt:apply-templates select="__Items"/>
<xslt:apply-templates select="pattern"/>
<xslt:apply-templates select="enum"/>
</xslt:template>
https://xsltfiddle.liberty-development.net/gWvjQgr
正如 Michael Kay 在评论中指出的那样,处理 XSD 模式通常是一项相当复杂的任务,因此将上面的内容作为一个简单示例,旨在解决示例中显示的特定问题 input/output.
我有 XSD 架构,我将其用作生成 XSLT 的源,该 XSLT 根据架构重新排序 XML 文件中的元素(基本上,使用 XSLT 从 XSD).我需要删除 XSD.
中 xs:choice 元素(也可以嵌套)中多次出现的元素我的 XML 有很多可选字段,所以我使用 choice 将它们分组,因为它们中的一些一起出现。选择是问题的根源,因为某些元素在选择元素内部重复并冒泡到生成的 XSLT 模板。
编辑: 我试图通过将 complexType 保存在一个变量中来使用多次传递。但是我不知道如何在特定的命名空间上进行身份转换。
XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://test.example.com/xsd" elementFormDefault="qualified">
<xs:element name="__Schema">
<xs:complexType>
<xs:choice>
<xs:element ref="ref"/>
<xs:sequence>
<xs:element ref="schema"/>
<xs:element minOccurs="0" ref="type"/>
<xs:element minOccurs="0" ref="description"/>
<xs:choice>
<xs:element ref="allOf"/>
<xs:element ref="__Property"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:element ref="type"/>
<xs:element ref="__Items"/>
</xs:sequence>
<xs:choice>
<xs:element ref="pattern"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="enum"/>
</xs:choice>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="description" type="xs:string"/>
<xs:element name="schema" type="xs:NCName"/>
<xs:element name="ref" type="xs:string"/>
<xs:element name="allOf" substitutionGroup="oneOf"/>
<xs:element name="type" type="xs:string"/>
<xs:element name="__Property" type="xs:string"/>
<xs:element name="enum" type="xs:string"/>
<xs:element name="__Items" type="xs:string"/>
<xs:element name="oneOf" type="xs:string"/>
<xs:element name="pattern" type="xs:string"/>
</xs:schema>
我的模板:
<?xml version="1.0" encoding="UTF-8"?>
<xslt:stylesheet version="2.0"
xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xt="http://www.w3.org/1999/XSL/TransformAlias">
<xslt:output method="xml" indent="yes"/>
<xslt:namespace-alias stylesheet-prefix="xt" result-prefix="xslt" />
<xslt:template match="*[@name and @substitutionGroup]"/>
<xslt:template match="xs:element[@name and not(@substitutionGroup) and not(@group)]">
<xslt:element name="xslt:template">
<xslt:attribute name="match">
<xslt:value-of select="string-join(@name|../xs:element[@substitutionGroup=current()/@name]/@name, '|')"/>
</xslt:attribute>
<xslt:apply-templates select="*"/>
</xslt:element>
</xslt:template>
<xslt:template match="xs:element[@ref]">
<xslt:element name="xslt:apply-templates">
<xslt:attribute name="select">
<xslt:value-of select="@ref"/>
</xslt:attribute>
</xslt:element>
</xslt:template>
<xslt:template match="xs:group[@ref]">
<xslt:apply-templates select="//*[@name=current()/@ref]/*"/>
</xslt:template>
<xslt:template match="xs:group[@name]"/>
<xslt:template match="xs:choice|xs:sequence|xs:complexType">
<xslt:apply-templates select="*"/>
</xslt:template>
<xslt:template match="xs:schema">
<xt:stylesheet version="2.0">
<xt:output method="text" indent="no"/>
<xslt:apply-templates select="*"/>
</xt:stylesheet>
</xslt:template>
</xslt:stylesheet>
目前,结果如下:
<xslt:template match="__Schema">
<xslt:apply-templates select="ref"/>
<xslt:apply-templates select="schema"/>
<xslt:apply-templates select="type"/>
<xslt:apply-templates select="description"/>
<xslt:apply-templates select="allOf"/>
<xslt:apply-templates select="__Property"/>
<xslt:apply-templates select="type"/>
<xslt:apply-templates select="__Items"/>
<xslt:apply-templates select="pattern"/>
<xslt:apply-templates select="enum"/>
</xslt:template>
我需要第二个 select="type"
消失,同时保留所有其他元素的顺序。我不想创建管道。
对于该示例,如果您添加
<xslt:key name="choice-ref" match="xs:choice//xs:element[@ref]" use="@ref"/>
<xslt:template match="xs:choice//xs:element[@ref][not(. is key('choice-ref', @ref, ancestor::xs:choice[1])[1])]" priority="10"/>
你得到
<xslt:template match="__Schema">
<xslt:apply-templates select="ref"/>
<xslt:apply-templates select="schema"/>
<xslt:apply-templates select="type"/>
<xslt:apply-templates select="description"/>
<xslt:apply-templates select="allOf"/>
<xslt:apply-templates select="__Property"/>
<xslt:apply-templates select="__Items"/>
<xslt:apply-templates select="pattern"/>
<xslt:apply-templates select="enum"/>
</xslt:template>
https://xsltfiddle.liberty-development.net/gWvjQgr
正如 Michael Kay 在评论中指出的那样,处理 XSD 模式通常是一项相当复杂的任务,因此将上面的内容作为一个简单示例,旨在解决示例中显示的特定问题 input/output.