How to read Xsd-Annotations from Xsd-Schema using Apache XMLBeans?

别说谁变了你拦得住时间么 提交于 2019-12-24 23:22:52

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!