在Java中,如何解析xml架构(xsd)以了解在给定元素处的有效内容?

时间:2011-11-26 23:59:38

标签: java xsd

我希望能够读取XML模式(即xsd),并从中了解当我浏览它时有效的属性,子元素,值。

例如,假设我有一个xsd,这个xml将验证:

<root>
  <element-a type="something">
    <element-b>blah</element-b>
    <element-c>blahblah</element-c>
  </element-a>
</root>

我已经修改了几个库,我可以自信地将<root>作为根元素。除此之外,我迷路了。

给定一个元素我需要知道哪些子元素是必需的或允许的,属性,方面,选择等。使用上面的例子,我想知道element-a有一个属性type并且可能有孩子element-belement-c ...或者必须有孩子element-belement-c ...或者必须拥有其中一个......你得到的照片我希望。

我看过很多库,比如XSOM,Eclipse XSD,Apache XmlSchema,发现它们都是很好的示例代码。我对互联网的搜索也没有成功。

有没有人知道一个很好的例子,甚至是一本书,它演示了如何通过XML模式并找出在经过验证的XML文档中给定点的有效选项?

澄清

我不打算验证文档,而是希望了解给定点的选项以帮助创建或编辑文档。如果我在一份文件中知道“我在这里”,我想确定那时我能做些什么。 “插入元素A,B或C中的一个”或“附加属性'描述'”。

6 个答案:

答案 0 :(得分:4)

在java中验证XML的许多解决方案都使用JAXB API。有一个广泛的教程here。使用JAXB执行您正在寻找的内容的基本方法如下:

  1. 获取或创建XML模式以进行验证。
  2. 生成Java类以将XML绑定到使用{JAXB编译器的xjc
  3. 将java代码写入:
    1. 将XML内容作为输入流打开。
    2. 创建JAXBContextUnmarshaller
    3. 将输入流传递给Unmarshaller的{​​{1}}方法。
  4. 您可以阅读本教程的部分内容:

    1. Hello, world
    2. Unmarshalling XML

答案 1 :(得分:3)

这是一个很好的问题。虽然它已经老了,但我找不到可接受的答案。问题是我所知道的现有库(XSOMApache XmlSchema)被设计为对象模型。实现者无意提供任何实用方法 - 您应该考虑使用提供的对象模型自己实现它们。

让我们看看如何通过Apache XmlSchema来查询特定于上下文的元素。

您可以使用他们的tutorial作为起点。此外,Apache CFX框架为XmlSchemaUtils类提供了许多方便的代码示例。

首先,阅读图书馆教程所示的XmlSchemaCollection

XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection();
xmlSchemaCollection.read(inputSource, new ValidationEventHandler());

现在,XML Schema定义了两种数据类型:

  • 简单类型
  • 复杂类型

简单类型由XmlSchemaSimpleType类表示。处理它们很容易。阅读文档:https://ws.apache.org/commons/XmlSchema/apidocs/org/apache/ws/commons/schema/XmlSchemaSimpleType.html。但是,让我们看看如何处理复杂类型。让我们从一个简单的方法开始:

@Override
public List<QName> getChildElementNames(QName parentElementName) {
    XmlSchemaElement element = xmlSchemaCollection.getElementByQName(parentElementName);
    XmlSchemaType type = element != null ? element.getSchemaType() : null;

    List<QName> result = new LinkedList<>();
    if (type instanceof XmlSchemaComplexType) {
        addElementNames(result, (XmlSchemaComplexType) type);
    }
    return result;
}

XmlSchemaComplexType可能代表实际类型和extension元素。请参阅public static QName getBaseType(XmlSchemaComplexType type)课程的XmlSchemaUtils方法。

private void addElementNames(List<QName> result, XmlSchemaComplexType type) {
    XmlSchemaComplexType baseType = getBaseType(type);
    XmlSchemaParticle particle = baseType != null ? baseType.getParticle() : type.getParticle();

    addElementNames(result, particle);
}

处理XmlSchemaParticle时,请考虑它可以有多个实现。请参阅:https://ws.apache.org/commons/XmlSchema/apidocs/org/apache/ws/commons/schema/XmlSchemaParticle.html

private void addElementNames(List<QName> result, XmlSchemaParticle particle) {
    if (particle instanceof XmlSchemaAny) {

    } else if (particle instanceof XmlSchemaElement) {

    } else if (particle instanceof XmlSchemaGroupBase) {

    } else if (particle instanceof XmlSchemaGroupRef) {

    }
}

要记住的另一件事是元素可以是抽象的也可以是具体的。同样,JavaDocs是最好的指导。

答案 2 :(得分:1)

我看到你尝试过Eclipse XSD。您是否尝试过Eclipse Modeling Framework(EMF)?你可以:

Generating an EMF Model using XML Schema (XSD)

Create a dynamic instance from your metamodel(3.1使用动态实例创建工具)

这是为了探索xsd。您可以创建根元素的动态实例,然后可以右键单击元素并创建子元素。在那里你会看到可能的子元素等等。

至于将创建的EMF模型保存到xml编译的xsd:我必须查找它。我认为您可以使用JAXB(How to use EMF to read XML file?)。


一些参考:

EMF: Eclipse Modeling Framework, 2nd Edition(由创作者撰写)
Eclipse Modeling Framework (EMF)
Discover the Eclipse Modeling Framework (EMF) and Its Dynamic Capabilities
Creating Dynamic EMF Models From XSDs and Loading its Instances From XML as SDOs

答案 3 :(得分:0)

这取决于你的xsd是如何复杂的,但基本上是。

如果你有

<Document>
<Header/>
<Body/>
<Document>

而且你想找出你可以使用标题的可爱儿童的位置(考虑名称空间) Xpath会让你寻找'/ element [name =“Document”] / element [name =“Header”]'

之后,这取决于你想要做多少。您可能会发现编写或查找将xsd加载到DOM类型结构中的内容更容易。 当然,你可能会在xsd,choice,sequence,any,attributes,complexType,SimpleContent,annotation中找到各种各样的东西。

充满乐趣的时间。

答案 4 :(得分:0)

答案 5 :(得分:0)

这是一个关于如何使用XSOM解析XSD的相当完整的示例:

import java.io.File;
import java.util.Iterator;
import java.util.Vector;

import org.xml.sax.ErrorHandler;

import com.sun.xml.xsom.XSComplexType;
import com.sun.xml.xsom.XSElementDecl;
import com.sun.xml.xsom.XSFacet;
import com.sun.xml.xsom.XSModelGroup;
import com.sun.xml.xsom.XSModelGroupDecl;
import com.sun.xml.xsom.XSParticle;
import com.sun.xml.xsom.XSRestrictionSimpleType;
import com.sun.xml.xsom.XSSchema;
import com.sun.xml.xsom.XSSchemaSet;
import com.sun.xml.xsom.XSSimpleType;
import com.sun.xml.xsom.XSTerm;
import com.sun.xml.xsom.impl.Const;
import com.sun.xml.xsom.parser.XSOMParser;
import com.sun.xml.xsom.util.DomAnnotationParserFactory;

public class XSOMNavigator
{
    public static class SimpleTypeRestriction
    {
        public String[] enumeration = null;
        public String   maxValue    = null;
        public String   minValue    = null;
        public String   length      = null;
        public String   maxLength   = null;
        public String   minLength   = null;
        public String[] pattern     = null;
        public String   totalDigits = null;
        public String   fractionDigits = null;
        public String   whiteSpace = null;

        public String toString()
        {
            String enumValues = "";
            if (enumeration != null)
            {
                for(String val : enumeration)
                {
                    enumValues += val + ", ";
                }
                enumValues = enumValues.substring(0, enumValues.lastIndexOf(','));
            }

            String patternValues = "";
            if (pattern != null)
            {
                for(String val : pattern)
                {
                    patternValues += "(" + val + ")|";
                }
                patternValues = patternValues.substring(0, patternValues.lastIndexOf('|'));
            }
            String retval = "";
            retval += minValue    == null ? "" : "[MinValue  = "   + minValue      + "]\t";
            retval += maxValue    == null ? "" : "[MaxValue  = "   + maxValue      + "]\t";
            retval += minLength   == null ? "" : "[MinLength = "   + minLength     + "]\t";
            retval += maxLength   == null ? "" : "[MaxLength = "   + maxLength     + "]\t";
            retval += pattern     == null ? "" : "[Pattern(s) = "  + patternValues + "]\t";
            retval += totalDigits == null ? "" : "[TotalDigits = " + totalDigits   + "]\t";
            retval += fractionDigits == null ? "" : "[FractionDigits = " + fractionDigits   + "]\t";
            retval += whiteSpace  == null ? "" : "[WhiteSpace = "      + whiteSpace        + "]\t";          
            retval += length      == null ? "" : "[Length = "      + length        + "]\t";          
            retval += enumeration == null ? "" : "[Enumeration Values = "      + enumValues    + "]\t";

            return retval;
        }
    }

    private static void initRestrictions(XSSimpleType xsSimpleType, SimpleTypeRestriction simpleTypeRestriction)
    {
        XSRestrictionSimpleType restriction = xsSimpleType.asRestriction();
        if (restriction != null)
        {
            Vector<String> enumeration = new Vector<String>();
            Vector<String> pattern     = new Vector<String>();

            for (XSFacet facet : restriction.getDeclaredFacets())
            {
                if (facet.getName().equals(XSFacet.FACET_ENUMERATION))
                {
                    enumeration.add(facet.getValue().value);
                }
                if (facet.getName().equals(XSFacet.FACET_MAXINCLUSIVE))
                {
                    simpleTypeRestriction.maxValue = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_MININCLUSIVE))
                {
                    simpleTypeRestriction.minValue = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_MAXEXCLUSIVE))
                {
                    simpleTypeRestriction.maxValue = String.valueOf(Integer.parseInt(facet.getValue().value) - 1);
                }
                if (facet.getName().equals(XSFacet.FACET_MINEXCLUSIVE))
                {
                    simpleTypeRestriction.minValue = String.valueOf(Integer.parseInt(facet.getValue().value) + 1);
                }
                if (facet.getName().equals(XSFacet.FACET_LENGTH))
                {
                    simpleTypeRestriction.length = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_MAXLENGTH))
                {
                    simpleTypeRestriction.maxLength = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_MINLENGTH))
                {
                    simpleTypeRestriction.minLength = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_PATTERN))
                {
                    pattern.add(facet.getValue().value);
                }
                if (facet.getName().equals(XSFacet.FACET_TOTALDIGITS))
                {
                    simpleTypeRestriction.totalDigits = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_FRACTIONDIGITS))
                {
                    simpleTypeRestriction.fractionDigits = facet.getValue().value;
                }
                if (facet.getName().equals(XSFacet.FACET_WHITESPACE))
                {
                    simpleTypeRestriction.whiteSpace = facet.getValue().value;
                }
            }
            if (enumeration.size() > 0)
            {
                simpleTypeRestriction.enumeration = enumeration.toArray(new String[] {});
            }
            if (pattern.size() > 0)
            {
                simpleTypeRestriction.pattern = pattern.toArray(new String[] {});
            }
        }
    }

    private static void printParticle(XSParticle particle, String occurs, String absPath, String indent)
    {
        boolean repeats = particle.isRepeated();
        occurs = "  MinOccurs = " + particle.getMinOccurs() + ", MaxOccurs = " + particle.getMaxOccurs() + ", Repeats = " + Boolean.toString(repeats);
        XSTerm term = particle.getTerm();
        if (term.isModelGroup())
        {
            printGroup(term.asModelGroup(), occurs, absPath, indent);    
        }
        else if(term.isModelGroupDecl())
        {
            printGroupDecl(term.asModelGroupDecl(), occurs, absPath, indent);    
        }
        else if (term.isElementDecl())
        {
            printElement(term.asElementDecl(), occurs, absPath, indent);
        }
    }

    private static void printGroup(XSModelGroup modelGroup, String occurs, String absPath, String indent)
    {
        System.out.println(indent + "[Start of Group " + modelGroup.getCompositor() + occurs + "]" );
        for (XSParticle particle : modelGroup.getChildren())
        {
            printParticle(particle, occurs, absPath, indent + "\t");
        }
        System.out.println(indent + "[End of Group " + modelGroup.getCompositor() + "]");
    }

    private static void printGroupDecl(XSModelGroupDecl modelGroupDecl, String occurs, String absPath, String indent)
    {
        System.out.println(indent + "[GroupDecl " + modelGroupDecl.getName() + occurs + "]");
        printGroup(modelGroupDecl.getModelGroup(), occurs, absPath, indent);
    }

    private static void printComplexType(XSComplexType complexType, String occurs, String absPath, String indent)
    {
        System.out.println();
        XSParticle particle = complexType.getContentType().asParticle();
        if (particle != null)
        {
            printParticle(particle, occurs, absPath, indent);
        }
    }

    private static void printSimpleType(XSSimpleType simpleType, String occurs, String absPath, String indent)
    {
        SimpleTypeRestriction restriction = new SimpleTypeRestriction();
        initRestrictions(simpleType, restriction);
        System.out.println(restriction.toString());
    }

    public static void printElement(XSElementDecl element, String occurs, String absPath, String indent)
    {
        absPath += "/" + element.getName();
        String typeName = element.getType().getBaseType().getName();
        if(element.getType().isSimpleType() && element.getType().asSimpleType().isPrimitive())
        {
            // We have a primitive type - So use that instead
            typeName = element.getType().asSimpleType().getPrimitiveType().getName();
        }

        boolean nillable = element.isNillable();
        System.out.print(indent + "[Element " + absPath + "   " + occurs + "] of type [" + typeName + "]" + (nillable ? " [nillable] " : ""));
        if (element.getType().isComplexType())
        {
            printComplexType(element.getType().asComplexType(), occurs, absPath, indent);
        }
        else
        {
            printSimpleType(element.getType().asSimpleType(), occurs, absPath, indent);
        }
    }

    public static void printNameSpace(XSSchema s, String indent)
    {
        String nameSpace = s.getTargetNamespace();

        // We do not want the default XSD namespaces or a namespace with nothing in it
        if(nameSpace == null || Const.schemaNamespace.equals(nameSpace) || s.getElementDecls().isEmpty())
        {
            return;
        }

        System.out.println("Target namespace: " + nameSpace);
        Iterator<XSElementDecl> jtr = s.iterateElementDecls();
        while (jtr.hasNext())
        {
            XSElementDecl e = (XSElementDecl) jtr.next();

            String occurs  = "";
            String absPath = "";

            XSOMNavigator.printElement(e, occurs, absPath,indent);
            System.out.println();
        }
    }

    public static void xsomNavigate(File xsdFile)
    {
        ErrorHandler    errorHandler    = new ErrorReporter(System.err);
        XSSchemaSet     schemaSet = null;

        XSOMParser parser = new XSOMParser();
        try
        {
            parser.setErrorHandler(errorHandler);
            parser.setAnnotationParser(new DomAnnotationParserFactory());
            parser.parse(xsdFile);
            schemaSet = parser.getResult();
        }
        catch (Exception exp)
        {
            exp.printStackTrace(System.out);
        }

        if(schemaSet != null)
        {
            // iterate each XSSchema object. XSSchema is a per-namespace schema.
            Iterator<XSSchema> itr = schemaSet.iterateSchema();
            while (itr.hasNext())
            {
                XSSchema s = (XSSchema) itr.next();
                String indent  = "";
                printNameSpace(s, indent);
            }
        }
    }

    public static void printFile(String fileName)
    {
        File fileToParse = new File(fileName);
        if (fileToParse != null && fileToParse.canRead())
        {
            xsomNavigate(fileToParse);
        }
    }
}

使用错误报告器:

import java.io.OutputStream;
import java.io.PrintStream;
import java.text.MessageFormat;

import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class ErrorReporter implements ErrorHandler {

    private final PrintStream out;

    public ErrorReporter( PrintStream o ) { this.out = o; }
    public ErrorReporter( OutputStream o ) { this(new PrintStream(o)); }

    public void warning(SAXParseException e) throws SAXException {
        print("[Warning]",e);
    }

    public void error(SAXParseException e) throws SAXException {
        print("[Error  ]",e);
    }

    public void fatalError(SAXParseException e) throws SAXException {
        print("[Fatal  ]",e);
    }

    private void print( String header, SAXParseException e ) {
        out.println(header+' '+e.getMessage());
        out.println(MessageFormat.format("   line {0} at {1}",
            new Object[]{
                Integer.toString(e.getLineNumber()),
                e.getSystemId()}));
    }
}

主要用途:

公共类WDXSOMParser {

    public static void main(String[] args)
    {
        String fileName = null;
        if(args != null && args.length > 0 && args[0] != null)
            fileName = args[0];
        else
        fileName = "C:\\xml\\CollectionComments\\CollectionComment1.07.xsd";
        //fileName = "C:\\xml\\PropertyListingContractSaleInfo\\PropertyListingContractSaleInfo.xsd";
        //fileName = "C:\\xml\\PropertyPreservation\\PropertyPreservation.xsd";

        XSOMNavigator.printFile(fileName);
    }
}