跨嵌套元素的 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.