В Java, как я могу разобрать XML-схему (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-b
а также element-c
... или должны иметь детей element-b
а также element-c
... или, должно быть, по одному на каждого... ты получаешь картинку, я надеюсь.
Я просмотрел многочисленные библиотеки, такие как XSOM, Eclipse XSD, Apache XmlSchema, и обнаружил, что у них все не хватает хорошего примера кода. Мой поиск в Интернете также не увенчался успехом.
Кто-нибудь знает хороший пример или даже книгу, которая демонстрирует, как пройти через схему XML и выяснить, какие будут допустимые параметры в данной точке в проверенном документе XML?
осветление
Я не собираюсь проверять документ, скорее я хотел бы знать параметры в данный момент, чтобы помочь в создании или редактировании документа. Если я знаю "я здесь" в документе, я бы хотел определить, что я могу сделать в этот момент. Msgstr "Вставить один из элементов A, B или C" или "прикрепить атрибут 'description'".
6 ответов
Многие из решений для проверки XML в java используют JAXB API. Здесь доступно обширное руководство. Основной рецепт для выполнения того, что вы ищете с JAXB, заключается в следующем:
- Получите или создайте схему XML для проверки.
- Генерация Java-классов для привязки XML к использованию
xjc
Компилятор JAXB - Написать код Java для:
- Откройте содержимое XML в качестве входного потока.
- Создать
JAXBContext
а такжеUnmarshaller
- Передайте входной поток в
Unmarshaller
"sunmarshal
метод.
Части урока, которые вы можете прочитать для этого:
Это хороший вопрос. Хотя, он старый, я не нашел приемлемого ответа. Дело в том, что существующие библиотеки, о которых я знаю ( XSOM, Apache XmlSchema), спроектированы как объектные модели. Разработчики не собирались предоставлять какие-либо служебные методы - вам следует рассмотреть возможность их реализации самостоятельно с использованием предоставленной объектной модели.
Давайте посмотрим, как запросить контекстно-зависимые элементы можно с помощью Apache XmlSchema.
Вы можете использовать их учебник в качестве отправной точки. Кроме того, платформа Apache CFX предоставляет классу XmlSchemaUtils множество полезных примеров кода.
Прежде всего, прочитайте XmlSchemaCollection
как показано в руководстве по библиотеке:
XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection();
xmlSchemaCollection.read(inputSource, new ValidationEventHandler());
Теперь XML-схема определяет два типа типов данных:
- Простые типы
- Сложные типы
Простые типы представлены 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 являются лучшим руководством.
Это довольно полный пример того, как анализировать XSD с помощью XSOM:
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);
}
}
}
А для вашего Error Reporter используйте:
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);
}
}
Я вижу, вы пробовали Eclipse XSD. Вы пробовали Eclipse Modeling Framework (EMF)? Вы можете:
Генерация модели EMF с использованием XML-схемы (XSD)
Создайте динамический экземпляр из вашей метамодели (3.1 С помощью инструмента создания динамического экземпляра)
Это для изучения XSD. Вы можете создать динамический экземпляр корневого элемента, затем вы можете щелкнуть правой кнопкой мыши по элементу и создать дочерний элемент. Там вы увидите, что такое возможный дочерний элемент и так далее.
Что касается сохранения созданной модели EMF в xsd, соответствующий xml: я должен поискать его. Я думаю, что вы можете использовать JAXB для этого ( Как использовать EMF для чтения XML-файла?).
Некоторые ссылки:
EMF: Eclipse Modeling Framework, 2-е издание (написано создателями)
Eclipse Modeling Framework (EMF)
Познакомьтесь с Eclipse Modeling Framework (EMF) и его динамическими возможностями
Создание динамических моделей EMF из XSD и загрузка их экземпляров из XML в виде SDO
Это хорошая работа, в зависимости от того, насколько сложен ваш xsd, но в основном.
если у тебя есть
<Document>
<Header/>
<Body/>
<Document>
И вы хотели выяснить, где находятся допустимые дочерние элементы заголовка (с учетом пространств имен), в Xpath вам нужно искать '/element[name="Document"]/element[name="Header"]'
После этого это зависит от того, сколько вы хотите сделать. Возможно, вам будет проще написать или найти что-то, что загружает xsd в структуру типа DOM. Конечно, вы можете найти все виды вещей под этим элементом в xsd, выбор, последовательность, любые, атрибуты, complexType, SimpleContent, аннотации.
Много времени, требующего веселья.
Посмотри на это! Как разобрать схему с помощью XOM Parser.