#xml #perl #xsd
#xml #perl #xsd
Вопрос:
Мне нужно создать XSD-схему на основе XML-файла. Существуют ли какие-либо модули Perl, которые могут это сделать?
Комментарии:
1. Связанный с этим вопросом: для инструмента Java см. trang . Для обратного направления см. XML-Pastor .
2. XSD-файл, сгенерированный XML-файлом, не имеет большой ценности. Можно смоделировать только структуру XML-файла. В XSD-файле не будет никаких ограничений, потому что вы не можете догадаться, что 2011 — это год, и поэтому невозможно определить какие-либо ограничения. Удовлетворит ли вашим требованиям XSD-файл, который моделирует только структуру?
Ответ №1:
Вы можете создать XSD с помощью преобразования XSL, используя любой процессор XSLT. Смотрите XML::XSLT
XSD-файл содержит два типа элементов: простой и сложный. Все конечные узлы должны быть переведены в элементы простого типа, а остальные должны быть переведены в сложные типы. Конечные узлы — это узлы без каких-либо потомков. Соответствующий XPath //*[not(descendant::element())]
. Следующий XSLT реализует этот подход:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsl:for-each select="//*[not(descendant::element())]">
<xsl:element name="xs:element">
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xsl:element>
</xsl:for-each>
<xsl:for-each select="//*[descendant::element()]">
<xsl:element name="xs:element">
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xs:complexType>
<xs:sequence>
<xsl:for-each select="child::*">
<xsl:element name="xs:element">
<xsl:attribute name="ref">
<xsl:value-of select="name()"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</xs:sequence>
</xs:complexType>
</xsl:element>
</xsl:for-each>
</xs:schema>
</xsl:template>
</xsl:stylesheet>
Следующий пример:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<firstname>Peter</firstname>
<lastname>Pan</lastname>
<born>
<year>1904</year>
<month>12</month>
<day>27</day>
</born>
</person>
Создаст следующую схему:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="firstname">
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:element>
<xs:element name="lastname">
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:element>
<xs:element name="year">
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:element>
<xs:element name="month">
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:element>
<xs:element name="day">
<xs:simpleType>
<xs:restriction base="xs:string"/>
</xs:simpleType>
</xs:element>
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element ref="firstname"/>
<xs:element ref="lastname"/>
<xs:element ref="born"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="born">
<xs:complexType>
<xs:sequence>
<xs:element ref="year"/>
<xs:element ref="month"/>
<xs:element ref="day"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Комментарии:
1. У меня работает! Поскольку вы на самом деле не используете какие-либо функции XSLT 2.0, вы могли бы перейти к гораздо более распространенному 1.0. Вам нужно будет только изменить
descendant::element()
наdescendant::*
.2. Также смотрите XML::LibXSLT , который является вашим лучшим выбором в Perl при выполнении XSLT.