Restrict tag insertion in XML

My question is related to Java. I have an xml which is initially valid as per xsd, I have used DOM parser and got a Document object out of it (I am using JAXP). Now, I want to disallow insertion of invalid xml element. So, when I try doing something like appendChild() I should get an exception if the element is invalid as per schema.

I have set the schema at the factory level before getting the dom. However, it seems to be fine with insertion of invalid elements. I only get to know that my document is incorrect when I am using validation api to check the validity of Document but that is happening at the end.

Here is the XML

<?xml version="1.0" encoding="UTF-8"?>

<Company xmlns="uri:Trial">
  <Business>
    <APAC>tns:APAC</APAC>
  </Business>  

  <NonBusiness>
    <Facilities>tns:Facilities</Facilities>
  </NonBusiness>
</Company>

The xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="uri:Trial"
    xmlns:tns="uri:Trial" elementFormDefault="qualified"     attributeFormDefault="qualified">

    <element name="Company" type="tns:MyComplexType"></element>


    <complexType name="MyComplexType">
        <sequence>
            <element ref="tns:Business"></element>
            <element ref="tns:NonBusiness"></element>
        </sequence>
    </complexType>

    <element name="Business" type="tns:BusinessType"></element>




    <element name="APAC" type="string"></element>

    <element name="AUS" type="string"></element>

    <element name="NonBusiness" type="tns:NonBusinessType"></element>

    <element name="Facilities" type="string"></element>



    <complexType name="BusinessType">
            <choice>
            <element ref="tns:APAC"></element>
            <element ref="tns:AUS"></element>
        </choice>
    </complexType>

    <complexType name="NonBusinessType">
        <sequence>
            <element ref="tns:Facilities"></element>
        </sequence>
    </complexType>
</schema>

The java

public class MainJAXPValidation {

public static void main(String[] args) throws Exception {

    File fxml = new File ("xmls/Trial.xml");
    File fxsd = new File ("xmls/Trial.xsd");



    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = sf.newSchema(new StreamSource(fxsd));

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setSchema(schema);
    dbf.setNamespaceAware(true);
//  dbf.setValidating(true);
    DocumentBuilder db = dbf.newDocumentBuilder();

    Document doc = db.parse(fxml);

    Node tempNode = doc.createElement("SomeChild");

    doc.appendChild(tempNode);

    DOMSource ds = new DOMSource(doc);

    Validator validator = schema.newValidator();

    validator.validate(ds);

}

}

Answers


Can I suggest an alternative... Have a custom class say, MyDocument which extends DocumentImpl. In your class, override the appendChild and other necessary methods. In your overridden method, you can do the validation and throw runtime exceptions.

  import com.sun.org.apache.xerces.internal.dom.DocumentImpl;
public class MyDocument extends DocumentImpl{

    Document document;
    Schema schema;

    public MyDocument(File xmlFile,File schemaFile) throws SAXException, IOException, ParserConfigurationException {
        this.document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        this.schema = sf.newSchema(new StreamSource(schemaFile));

    }


    @Override
    public Node appendChild(Node newChild) throws DOMException {
//Validation    
return super.appendChild(newChild);
    }
}

Actually, there is a way for you to do that in JAXP. With DOM, each and every Node is also an EventTarget, so you can register an EventListener to your Document and work from there (your listener could throw an exception if a disallowed insertion takes place).

Of course, you may wish to attach an EventListener to a "narrower" scope than the entire document, for performance reasons.

Here's a good place to start: http://docs.oracle.com/javase/7/docs/api/index.html?org/w3c/dom/events/EventListener.html


Need Your Help

Loading images into windows phone app from external url

c# xaml image-processing windows-phone-8

I am trying to load some images from a particular url: http://www.example.com/Images/.