根据根元素创建XSD

时间:2015-06-15 10:51:14

标签: java xml parsing xsd

我有一个如下所示的XSD,我需要提取XSD中的所有根元素,并在java中以实际方式为每个根元素创建一个单独的XSD,是否有一些java库框架可以帮助我实现这一点。

<?xml version='1.0' encoding='windows-1252'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.org" targetNamespace="http://www.example.org" elementFormDefault="qualified">
   <xsd:complexType name="USAddress">
      <xsd:sequence>
         <xsd:element name="HouseNumber" type="xsd:string"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="OrderType">
      <xsd:sequence>
         <xsd:element name="orderID" type="xsd:string"/>
         <xsd:element name="billTo" type="USAddress"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="Customer">
      <xsd:complexType>
         <xsd:sequence>
            <xsd:element name="CustomerID" type="xsd:string"/>
            <xsd:element name="Address" type="USAddress"/>
         </xsd:sequence>
      </xsd:complexType>
   </xsd:element>
   <xsd:element name="Order" type="OrderType"/>
</xsd:schema>

TO

<?xml version='1.0' encoding='windows-1252'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.org" targetNamespace="http://www.example.org" elementFormDefault="qualified">
   <xsd:complexType name="USAddress">
      <xsd:sequence>
         <xsd:element name="HouseNumber" type="xsd:string"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="OrderType">
      <xsd:sequence>
         <xsd:element name="orderID" type="xsd:string"/>
         <xsd:element name="billTo" type="USAddress"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="Order" type="OrderType"/>
</xsd:schema>

<?xml version='1.0' encoding='windows-1252'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.org" targetNamespace="http://www.example.org" elementFormDefault="qualified">
   <xsd:complexType name="USAddress">
      <xsd:sequence>
         <xsd:element name="HouseNumber" type="xsd:string"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="Customer">
      <xsd:complexType>
         <xsd:sequence>
            <xsd:element name="CustomerID" type="xsd:string"/>
            <xsd:element name="Address" type="USAddress"/>
         </xsd:sequence>
      </xsd:complexType>
   </xsd:element>
</xsd:schema>

1 个答案:

答案 0 :(得分:2)

使用 XSL 2.0 ,您可以拥有多个输出文档,并可以定义每个文件名,文件内容等。默认 java 支持 XSL 2.0 远非完美,所以我使用了令人难以置信的 Saxon (你可以下载 saxon-he here,解压缩并添加 saxon9he.jar 到您的项目中。)

这是我所做的XSL 2.0示例,它使用用户launehis comment中公开的想法。因此它为每个元素生成一个输出模式,并为非元素(类型)的所有内容生成模式。每个新架构仅包含 xs:element ,并且具有 xs:include ,包括包含类型的架构。如果您熟悉XSL(查看xsl注释),这是一个非常简单(在我看来非常聪明)的方法,并且易于理解。

xsl.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="/">
        <xsl:for-each select="/*/*[local-name()='element']">
            <xsl:variable name="currentElement" select="."/>
            <!-- Create schema for every element containing only element, including types schema -->
            <xsl:result-document method="xml" href="schema_element_{@name}.xsd">
                <xsl:for-each select="/*[1]">
                    <xsl:copy>
                        <xsl:copy-of select="@*"/>
                        <xsl:element name="include" namespace="http://www.w3.org/2001/XMLSchema">
                            <xsl:attribute name="schemaLocation">schema_types.xsd</xsl:attribute>
                        </xsl:element> <!-- Include clause -->
                        <xsl:copy-of select="$currentElement"/> <!-- Only content is current xs:element -->
                    </xsl:copy>
                </xsl:for-each>
            </xsl:result-document>
        </xsl:for-each>

        <xsl:for-each select="/*[1]">
            <!-- Create types document containing all but root xs:element's -->
            <xsl:result-document method="xml" href="schema_types.xsd">
                <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <xsl:copy-of select="node()[local-name()!='element']"/>
                </xsl:copy>
            </xsl:result-document>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

所需的唯一java代码是调用 saxon 进行xsl转换,生成输出文件,其名称在 xsl 中动态派生。

Main.java

import java.io.File;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class Main { 
    public static void main(String[]args) throws Exception{
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Transformer transformer = tFactory.newTransformer(new StreamSource(new File("xsl.xsl")));
        transformer.transform(new StreamSource(new File("schema.xsd")), new StreamResult(System.out));
    }
}

使用您的示例模式,我的xsl并运行java代码,这些是使用这些文件名创建的文件(请注意,缩进可能会丢失):

schema_element_Customer.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.example.org" targetNamespace="http://www.example.org"
    elementFormDefault="qualified">
    <include xmlns="http://www.w3.org/2001/XMLSchema"
        schemaLocation="schema_types.xsd" />
    <xsd:element name="Customer">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="CustomerID" type="xsd:string" />
                <xsd:element name="Address" type="USAddress" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

schema_element_Order.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.example.org" targetNamespace="http://www.example.org"
    elementFormDefault="qualified">
    <include xmlns="http://www.w3.org/2001/XMLSchema"
        schemaLocation="schema_types.xsd" />
    <xsd:element name="Order" type="OrderType" />
</xsd:schema>

schema_types.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.example.org" targetNamespace="http://www.example.org"
    elementFormDefault="qualified">
    <xsd:complexType name="USAddress">
        <xsd:sequence>
            <xsd:element name="HouseNumber" type="xsd:string" />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="OrderType">
        <xsd:sequence>
            <xsd:element name="orderID" type="xsd:string" />
            <xsd:element name="billTo" type="USAddress" />
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

更新:输出到Map

的必要更改

必须更改输出到Map而不是文件系统中的文件:

基于this answer我意识到您可以添加一个设置以供每个结果文档通知,以便您可以将输出写入要实现OutputUriResolver的位置。所以我已经写了一个写入HashMap的那个:

import java.io.StringWriter;
import java.util.Map;
import javax.xml.transform.Result;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import net.sf.saxon.lib.OutputURIResolver;

public class HashMapSaverOutputUriResolver implements OutputURIResolver{
    private Map<String, String> results; // We save here
    public HashMapSaverOutputUriResolver(Map<String, String> map){
        this.results = map; // Set map
    }
    public OutputURIResolver newInstance() {
        return this;
    }
    public Result resolve(String href, String base) throws TransformerException { // We set to resolve the file to write to a stringResult that wraps a stringWritter
        StringWriter sw = new StringWriter(); // StringWritter 
        StreamResult sr = new StreamResult(sw); // StreamResult
        sr.setSystemId(href); // Id of the streamResult = href = fileName
        return sr;
    }
    public void close(Result result) throws TransformerException { // End of result:document transformed
        StreamResult sr = (StreamResult) result; // Get StreamResult
        StringWriter sw = (StringWriter) sr.getWriter(); // Get StreamWritter
        String href = sr.getSystemId(); // Get href (fileName)
        String content = sw.toString(); // Get string file-content
        this.results.put(href, content); // Save in map
    }
}

在主文件中,您只需添加两个新行(创建地图,并将正确的设置设置为与地图关联的OutputUriResolver)。

public static void main(String[] args) throws Exception {
    HashMap<String, String> results = new HashMap<String, String>(); // Your map        
    TransformerFactory tFactory = TransformerFactory.newInstance();
    tFactory.setAttribute("http://saxon.sf.net/feature/outputURIResolver", new HashMapSaverOutputUriResolver(results)); // Set OutputURIResolver
    Transformer transformer = tFactory.newTransformer(new StreamSource(new File("xsl.xsl")));
    transformer.transform(new StreamSource(new File("schema.xsd")), new StreamResult(System.out));
    // Once the transformation has finished the Map is filled
}