Я новичок в XSL, но нашел его довольно интересным. Я использую его для создания XSD, чтобы мы могли использовать привязку данных при взаимодействии с действительно старой системой, в которой отсутствует правильная схема.
Я застрял на чем-то, что я считаю довольно простой проблемой, но после нескольких часов тестирования и гугления (начав сомневаться в своих навыках Google здесь ...) я чувствую, что мне нужно спросить :-)
Учитывая этот XML:
<?xml version="1.0" encoding="UTF-8"?>
<classes>
<class>
<name>param1/stateSettings</name>
<list>
<options>
<default>0</default>
<option key="0" value="Disabled"/>
<option key="1" value="Enabled"/>
</options>
</list>
</class>
<class>
<name>param2/stateSettings</name>
<list>
<options>
<default>0</default>
<option key="1" value="Enabled"/>
<option key="0" value="Disabled"/>
</options>
</list>
</class>
<class>
<name>param3/stateSettings</name>
<list>
<options>
<default>1</default>
<option key="1" value="Enabled"/>
<option key="0" value="Disabled"/>
</options>
</list>
</class>
<class>
<name>param4/stateSettings</name>
<list>
<options>
<default>0</default>
<option key="1" value="Disabled"/>
<option key="0" value="Enabled"/>
</options>
</list>
</class>
</classes>
Я бы (в конечном итоге) получил этот вывод:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="stateSettingsType">
<xs:annotation>
<xs:documentation>
<replaces>param1/stateSettings</replaces>
<replaces>param2/stateSettings</replaces>
<replaces>param3/stateSettings</replaces>
<grouping-key value="0:1:Disabled:Enabled"/>
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="1">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Enabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="0">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Disabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="stateSettings2Type">
<xs:annotation>
<xs:documentation>
<replaces>param4/stateSettings</replaces>
<grouping-key value="1:0:Disabled:Enabled"/>
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="1">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Disabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="0">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Enabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:schema>
(ключ группировки здесь только для справки, содержание не имеет значения)
Мой 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" version="2.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:output method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="options">
<xsl:apply-templates select="option"/>
</xsl:template>
<xsl:template match="option">
<xs:enumeration value="{@key}">
<xs:annotation>
<xs:appinfo>
<xsl:element name="dataBinding">
<xsl:attribute name="enum" select="@value"/>
</xsl:element>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xsl:template>
<xsl:template match="name">
<xsl:element name="replaces">
<xsl:value-of select="../name"/>
</xsl:element>
</xsl:template>
<xsl:template match="classes">
<xsl:for-each-group select="class" group-by="substring-after(name, '/')">
<xsl:variable name="typeName" select="current-grouping-key()"/>
<xsl:for-each-group select="current-group()/list" group-by="string-join((options/option/@key, options/option/@value), ':')">
<xsl:variable name="newTypeName">
<xsl:choose>
<xsl:when test="position() gt 1">
<xsl:value-of select="string-join(($typeName,format-number(position(),'#'),'Type'),'')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="string-join(($typeName,'Type'),'')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xs:simpleType name="{$newTypeName}">
<xs:annotation>
<xs:documentation>
<xsl:for-each select="current-group()">
<xsl:apply-templates select="../name"/>
</xsl:for-each>
<xsl:element name="grouping-key">
<xsl:attribute name="value" select="current-grouping-key()"/>
</xsl:element>
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xsl:apply-templates select="options"/>
</xs:restriction>
</xs:simpleType>
</xsl:for-each-group>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="/">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:apply-templates select="classes"/>
</xs:schema>
</xsl:template>
</xsl:stylesheet>
Мой текущий вывод XSL (XSD):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="stateSettingsType">
<xs:annotation>
<xs:documentation>
<replaces>param1/stateSettings</replaces>
<grouping-key value="0:1:Disabled:Enabled"/>
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="0">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Disabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="1">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Enabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="stateSettings2Type">
<xs:annotation>
<xs:documentation>
<replaces>param2/stateSettings</replaces>
<replaces>param3/stateSettings</replaces>
<grouping-key value="1:0:Enabled:Disabled"/>
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="1">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Enabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="0">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Disabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="stateSettings3Type">
<xs:annotation>
<xs:documentation>
<replaces>param4/stateSettings</replaces>
<grouping-key value="1:0:Disabled:Enabled"/>
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="1">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Disabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="0">
<xs:annotation>
<xs:appinfo>
<dataBinding enum="Enabled"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Так в чем моя проблема? Ну, на самом деле есть две вещи, которые нужно исправить, чтобы получить «окончательный» результат, но мне достаточно решить только одну.
Проблема 1 связана с группировкой, выполненной в группе для каждой группы. Мне нужно сгруппировать на основе некоторых содержимого параметров. Моя текущая группировка на основе строк чувствительна к порядку элементов option. Элементы param1, param2 и param3 одинаковы и должны быть реорганизованы до одного простого типа в XSD. param4 имеет перевернутый ключ/значение и должен быть создан как новый simpleType (и да, старая система фактически использует этот тип "схемы"... Совсем не сбивает с толку :-D) Я могу не основывайте группировку на всех параметрах, так как там есть другие вещи, которые не имеют отношения к этой области и испортят группировку.
Проблема 2 больше косметическая. Было бы хорошо, если бы первый simpleType заменял наиболее распространенные типы, т.е. если у меня есть 58 одинаковых class и 2 несколько отличающихся, я бы хотел, чтобы наиболее распространенный simpleType имел имя без последовательности количество.
(Обратите внимание, что элементы default не имеют отношения к созданию типов в XSD, но я вернусь к ним на более позднем этапе в моем XSL при создании элементов xsd, которые могут иметь значения по умолчанию)
Я надеюсь, что кто-то достаточно любезен, чтобы сказать мне, что мне не хватает. Пожалуйста, дайте мне знать о любых других проблемах, которые могут возникнуть в моем коде :-)