问题
I read a xsd-schema file using Apache XMLBeans, iterating over all SchemaProperties beginning with the root element. At each SchemaProperty I am looking for an annotation with: schemaProperty.getType().getAnnotation(), but I don't find any annotation. (java code below)
I examine for example the following xsd-file:
Figure of xsd structure:
Xsd source code:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="ExterneDaten" type="ExterneDaten">
<xs:annotation>
<xs:documentation>annotation for ExterneDaten</xs:documentation>
</xs:annotation>
</xs:element>
<xs:complexType name="ExterneDaten">
<xs:annotation>
<xs:documentation>annotation for Type ExterneDaten</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="value1" type="xs:string">
<xs:annotation>
<xs:documentation>annotation for value1</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="isTest" type="xs:boolean">
<xs:annotation>
<xs:documentation>annotation for boolean attribute isTest</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
I examine the xsd with my function: MyXsdReader.readAllAnnotationsFromXsd(String schema);
Here is the java code:
public class MyXsdReader
{
public static void readAllAnnotationsFromXsd(String newSchema)
{
try
{
SchemaTypeLoader loader = XmlBeans.typeLoaderForClassLoader(SchemaDocument.class.getClassLoader());
XmlObject[] xmlObjects = new XmlObject[1];
XmlOptions options = new XmlOptions();
options.setLoadLineNumbers().setLoadMessageDigest().setCharacterEncoding("utf-8");
options.setCompileDownloadUrls();
xmlObjects[0] = loader.parse(newSchema, null, options);
SchemaTypeSystem sts = XmlBeans.compileXsd(xmlObjects, XmlBeans.getBuiltinTypeSystem(), options);
readXsdRootElement(sts);
}
catch (Exception e)
{
System.out.println("makeXsdListRootEle(): Excpetion: " + e.getMessage());
}
}
private static void readXsdRootElement(SchemaTypeSystem sts)
{
SchemaGlobalElement[] globals = sts.globalElements();
if (globals != null && globals.length == 1)
{
SchemaGlobalElement sge = globals[0];
SchemaType st = sge.getType();
SchemaProperty[] properties = st.getProperties();
for (int k = 0; k < properties.length; k++)
{
SchemaProperty property = properties[k];
checkAnnotation(property);
if (property.isAttribute() == false)
{
readXsdProperty(property);
}
}
}
}
private static void readXsdProperty(SchemaProperty property)
{
SchemaProperty[] properties = property.getType().getProperties();
for (SchemaProperty schemaProperty : properties)
{
checkAnnotation(schemaProperty);
readXsdProperty(schemaProperty);
}
}
private static void checkAnnotation(SchemaProperty schemaProperty)
{
SchemaAnnotation annotation = schemaProperty.getType().getAnnotation();
if (annotation != null)
{
System.out.println(annotation.toString());
}
}
}
What do I have to do, to be able to read the annotations inside the xsd?
回答1:
I had the same requirement and was able to parse the Annotations in XSD as shown below.
Say the XSD is as follows:-
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="ExterneDaten" type="ExterneDaten">
<xs:annotation>
<xs:documentation>annotation for ExterneDaten</xs:documentation>
</xs:annotation>
</xs:element>
<xs:complexType name="ExterneDaten">
<xs:annotation>
<xs:documentation>annotation for Type ExterneDaten</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="value1" type="xs:string">
<xs:annotation>
<xs:documentation>annotation for value1</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="isTest" type="xs:boolean">
<xs:annotation>
<xs:documentation>annotation for boolean attribute isTest</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
Now, we have to create a custom Annotation Parser as follows:-
public class XSDAnnotaionParser extends AnnotationParser {
private StringBuilder documentation = new StringBuilder();
@Override
public ContentHandler getContentHandler(AnnotationContext context, String parentElementName, ErrorHandler handler,
EntityResolver resolver) {
return new ContentHandler() {
private boolean parsingDocumentation = false;
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (parsingDocumentation) {
documentation.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
//say you want to parse the text in "documentaion" tag in your xsd....this is where we scpecify the tag
if (localName.equals("documentation")) {
parsingDocumentation = false;
}
}
@Override
public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {
if (localName.equals("documentation")) {
parsingDocumentation = true;
}
}
@Override
public void setDocumentLocator(Locator locator) {
// TODO Auto-generated method stub
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void processingInstruction(String target, String data) throws SAXException {
// TODO Auto-generated method stub
}
@Override
public void skippedEntity(String name) throws SAXException {
// TODO Auto-generated method stub
}
};
}
@Override
public Object getResult(Object existing) {
return documentation.toString().trim();
}
}
Now we create a factory class for the custom annotation parser which we created above as follows:-
class AnnotationFactory implements AnnotationParserFactory {
@Override
public AnnotationParser create() {
return new XSDAnnotaionParser();
}
}
Now we add the custom annotation parser to XSOMParser which we use for parsing XSD as follows:-
XSOMParser parser = new XSOMParser();
parser.setAnnotationParser(new AnnotationFactory());
try {
parser.parse(xml);
} catch (SAXException ex) {
throw new SchemaException(ex);
}
For parsing the documentation tag we can use the code as below:-
XSSchemaSet schemaSet = null;
try {
schemaSet = parser.getResult();
} catch (SAXException ex) {
throw new SchemaException(ex);
}
Iterator<XSElementDecl> iterator = schemaSet.iterateElementDecls();
while (iterator.hasNext()) {
XSElementDecl elementDecl= (XSElementDecl) iterator.next();
XSComplexType eleCompDecl= elementDecl.getType().asComplexType();
if (eleCompDecl!= null) {
//we get the annotation here
XSAnnotation annotaion = eleCompDecl.getAnnotation();
//this will print the tezxt inside documentaion tag
System.out.println(annotaion.getAnnotation());
}
}
Code for reading annotaions inside attributes of an xsd is as follows :-
Collection<? extends XSAttributeUse> attributes= eleCompDecl.getAttributeUses();
Iterator<? extends XSAttributeUse> iterator = attributes.iterator();
while(attributes.hasNext()) {
XSAttributeUse next = attributes.next();
XSAttributeDecl attributeDecl = next.getDecl();
String desc = null;
if(attributeDecl != null) {
try {
desc = (String)attributeDecl.getAnnotation().getAnnotation();
System.out.println("the documentaion for the attribute is "+desc)
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
回答2:
I ran into the same problem and solved it for me with Apache xmlbeans in the way described below. The example is basically Groovy code but should be easy transferable to Java.
void parseDocumentations(File xsdFile) {
// load the xsd
XmlObject object = XmlObject.Factory.parse(xsdFile)
List<XmlObject> objectList = []
objectList.add(object)
// parse the xsd content to a object tree
SchemaTypeSystem sts = XmlBeans.compileXsd((XmlObject[])objectList.toArray(), XmlBeans.getBuiltinTypeSystem(), null)
def globalTypes = sts.globalTypes()
// iterate over the defined types in the xsd
for (SchemaType type: globalTypes) {
def annotation = type.getAnnotation()
if (annotation!=null) {
// get the sub xml nodes of the annotation node
def userInfos = annotation.userInformation
for (XmlObject userInfo: userInfos ) {
if (userInfo.getDomNode().localName=='documentation') {
// extract the text from documentation node
def documentationTxt = userInfo.getDomNode().getFirstChild().getNodeValue()
println documentationTxt
}
}
}
}
}
来源:https://stackoverflow.com/questions/48196744/how-to-read-xsd-annotations-from-xsd-schema-using-apache-xmlbeans