Package org.apache.padaf.xmpbox.parser

Source Code of org.apache.padaf.xmpbox.parser.XMPDocumentBuilder

/*****************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
****************************************************************************/

package org.apache.padaf.xmpbox.parser;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.padaf.xmpbox.CreateXMPMetadataException;
import org.apache.padaf.xmpbox.XMPMetadata;
import org.apache.padaf.xmpbox.schema.PDFAExtensionSchema;
import org.apache.padaf.xmpbox.schema.PDFAFieldDescription;
import org.apache.padaf.xmpbox.schema.SchemaDescription;
import org.apache.padaf.xmpbox.schema.XMPSchema;
import org.apache.padaf.xmpbox.type.AbstractSimpleProperty;
import org.apache.padaf.xmpbox.type.Attribute;
import org.apache.padaf.xmpbox.type.BadFieldValueException;
import org.apache.padaf.xmpbox.type.BooleanType;
import org.apache.padaf.xmpbox.type.ComplexProperty;
import org.apache.padaf.xmpbox.type.ComplexPropertyContainer;
import org.apache.padaf.xmpbox.type.DateType;
import org.apache.padaf.xmpbox.type.IntegerType;
import org.apache.padaf.xmpbox.type.RealType;
import org.apache.padaf.xmpbox.type.TextType;
import org.apache.padaf.xmpbox.type.ThumbnailType;
import org.apache.pdfbox.io.IOUtils;


/**
* Parse serialized XMP (in XML/RDF Format) to the XmpBox representation.
*
* @author a183132
*
*/
public class XMPDocumentBuilder {

  protected NSMapping nsMap;

  protected ThreadLocal<XMLStreamReader> reader = new ThreadLocal<XMLStreamReader>();

  protected List<XMPDocumentPreprocessor> preprocessors = new ArrayList<XMPDocumentPreprocessor>();

  public static final String BAG_NAME = "Bag";

  public static final String SEQ_NAME = "Seq";

  public static final String ALT_NAME = "Alt";

  public static final String VALUE_TYPE_NAME = "valueType";

  /**
   * Constructor of a XMPDocumentBuilder
   *
   * @throws XmpSchemaException
   *             When instancing schema object failed or in PDF/A Extension
   *             case, if its namespace miss
   */
  public XMPDocumentBuilder() throws XmpSchemaException {
    nsMap = new NSMapping();
  }

  /**
   * Parsing method. Return a XMPMetadata object with all elements read
   *
   * @param xmp
   *            serialized XMP
   * @return Metadata with all information read
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XmpSchemaException
   *             When instancing schema object failed or in PDF/A Extension
   *             case, if its namespace miss
   * @throws XmpUnknownValueTypeException
   *             When ValueType found not correspond to basic type and not has
   *             been declared in current schema
   * @throws XmpExpectedRdfAboutAttribute
   *             When rdf:Description not contains rdf:about attribute
   * @throws XmpXpacketEndException
   *             When xpacket end Processing Instruction is missing or is
   *             incorrect
   * @throws BadFieldValueException
   *             When treat a Schema associed to a schema Description in PDF/A
   *             Extension schema
   */

  public XMPMetadata parse(byte[] xmp) throws XmpParsingException,
  XmpSchemaException, XmpUnknownValueTypeException,
  XmpExpectedRdfAboutAttribute, XmpXpacketEndException,
  BadFieldValueException {

    if (!(this instanceof XMPDocumentPreprocessor)) {
      for (XMPDocumentPreprocessor processor : preprocessors) {
        NSMapping additionalNSMapping = processor.process(xmp);
        this.nsMap.importNSMapping(additionalNSMapping);       
      }
    }

    ByteArrayInputStream is = new ByteArrayInputStream(xmp);
    try {
      XMLInputFactory factory = XMLInputFactory.newInstance();
      reader.set(factory.createXMLStreamReader(is));

      // expect xpacket processing instruction
      expectNext(XMLStreamReader.PROCESSING_INSTRUCTION,
          "Did not find initial xpacket processing instruction");
      XMPMetadata metadata = parseInitialXpacket(reader.get().getPIData());

      // expect x:xmpmeta
      expectNextTag(XMLStreamReader.START_ELEMENT,
          "Did not find initial x:xmpmeta");
      expectName("adobe:ns:meta/", "xmpmeta");

      // expect rdf:RDF
      expectNextTag(XMLStreamReader.START_ELEMENT,
          "Did not find initial rdf:RDF");
      expectName("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF");

      nsMap.resetComplexBasicTypesDeclarationInEntireXMPLevel();
      // add all namespaces which could declare nsURI of a basicValueType
      // all others declarations are ignored
      int nsCount = reader.get().getNamespaceCount();
      for (int i = 0; i < nsCount; i++) {
        if (nsMap.isComplexBasicTypes(reader.get().getNamespaceURI(i))) {
          nsMap.setComplexBasicTypesDeclarationForLevelXMP(
              reader.get().getNamespaceURI(i),
              reader.get().getNamespacePrefix(i));
        }
      }

      // now work on each rdf:Description
      int type = reader.get().nextTag();
      while (type == XMLStreamReader.START_ELEMENT) {
        parseDescription(metadata);
        type = reader.get().nextTag();
      }

      // all description are finished
      // expect end of rdf:RDF
      expectType(XMLStreamReader.END_ELEMENT,
          "Expected end of descriptions");
      expectName("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF");

      // expect ending xmpmeta
      expectNextTag(XMLStreamReader.END_ELEMENT,
          "Did not find initial x:xmpmeta");
      expectName("adobe:ns:meta/", "xmpmeta");

      // expect final processing instruction
      expectNext(XMLStreamReader.PROCESSING_INSTRUCTION,
          "Did not find final xpacket processing instruction");
      // treats xpacket end
      if (!reader.get().getPITarget().equals("xpacket")) {
        throw new XmpXpacketEndException("Excepted PI xpacket");
      }
      String xpackData = reader.get().getPIData();
      // end attribute must be present and placed in first
      // xmp spec says Other unrecognized attributes can follow, but
      // should be ignored
      if (xpackData.startsWith("end=")) {
        // check value (5 for end='X')
        if (xpackData.charAt(5)!='r' && xpackData.charAt(5)!='w') {
          throw new XmpXpacketEndException(
              "Excepted xpacket 'end' attribute with value 'r' or 'w' ");
        }
      } else {
        // should find end='r/w'
        throw new XmpXpacketEndException(
            "Excepted xpacket 'end' attribute (must be present and placed in first)");
      }

      metadata.setEndXPacket(xpackData);
      // return constructed object
      return metadata;
    } catch (XMLStreamException e) {
      throw new XmpParsingException("An error has occured when processing the underlying XMP source", e);
    } finally {
      reader.remove();
      IOUtils.closeQuietly(is);
    }
  }

  /**
   * Parsing method using serialized xmp read from a stream
   *
   * @param is
   *            The stream to read
   * @return Metadata with all information read
   * @throws XmpParsingException
   *             When element expected not found When element expected not
   *             found
   * @throws XmpSchemaException
   *             When instancing schema object failed or in PDF/A Extension
   *             case, if its namespace miss
   * @throws XmpUnknownValueTypeException
   *             When ValueType found not correspond to basic type and not has
   *             been declared in current schema
   * @throws XmpExpectedRdfAboutAttribute
   *             When rdf:Description not contains rdf:about attribute
   * @throws XmpXpacketEndException
   *             When xpacket end Processing Instruction is missing or is
   *             incorrect
   * @throws BadFieldValueException
   *             When treat a Schema associed to a schema Description in PDF/A
   *             Extension schema
   */
  public XMPMetadata parse(InputStream input) throws XmpParsingException,
  XmpSchemaException, XmpUnknownValueTypeException,
  XmpExpectedRdfAboutAttribute, XmpXpacketEndException,
  BadFieldValueException {

    byte[] bos = getStreamAsByteArray(input);
    return parse(bos);
  }

  private byte[] getStreamAsByteArray(InputStream input) throws XmpParsingException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
      IOUtils.copy(input, bos);
    } catch (IOException e) {
      throw new XmpParsingException("An error has occured when processing the underlying XMP source", e);
    } finally {
      IOUtils.closeQuietly(bos);
      IOUtils.closeQuietly(input);
    }
    return bos.toByteArray();
  }

  public void addPreprocessor(XMPDocumentPreprocessor processor) {
    this.preprocessors.add(processor);
  }

  /**
   * Check InitialXPacket and build metadata object with these information
   *
   * @param data
   *            data corresponding to Initial XPacket Processing Instruction
   *            Processing Information corresponding to Inital XPacket data
   * @return Metadata with specified information
   * @throws XmpInitialXPacketParsingException
   *             When Initial XPacket missing or is incorrect
   * @throws CreateXMPMetadataException
   *             If DOM Document associated could not be created
   */
  protected XMPMetadata parseInitialXpacket(String data)
      throws XmpInitialXPacketParsingException,
      CreateXMPMetadataException {
    StringTokenizer tokens = new StringTokenizer(data, " ");
    String id = null;
    String begin = null;
    String bytes = null;
    String encoding = null;
    while (tokens.hasMoreTokens()) {
      String token = tokens.nextToken();
      if (!token.endsWith("\"") && !token.endsWith("\'")) {
        throw new XmpInitialXPacketParsingException(
            "Cannot understand PI data part : '" + token + "'");
      }
      String quote = token.substring(token.length()-1);
      int pos = token.indexOf("="+quote);
      if (pos <= 0) {
        throw new XmpInitialXPacketParsingException(
            "Cannot understand PI data part : '" + token + "'");
      }
      String name = token.substring(0, pos);
      String value = token.substring(pos + 2, token.length() - 1);
      if ("id".equals(name)) {
        id = value;
      } else if ("begin".equals(name)) {
        begin = value;
      } else if ("bytes".equals(name)) {
        bytes = value;
      } else if ("encoding".equals(name)) {
        encoding = value;
      } else {
        throw new XmpInitialXPacketParsingException(
            "Unknown attribute in xpacket PI : '" + token + "'");
      }
    }
    return new XMPMetadata(begin, id, bytes, encoding);
  }

  /**
   * Check the next element type. all comments are ignored.
   *
   * @param expectType
   *            Type of xml element expected
   * @param message
   *            Error message if problems occur
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected When DOM Element type
   *             found unexpected
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream When error
   *             during reading the rest of xmp stream
   */
  private void expectNext(int expectType, String message)
      throws XmpParsingException, XmpUnexpectedTypeException,
      XMLStreamException {
    try {
      int type = reader.get().next();
      while (type == XMLStreamReader.COMMENT || type == XMLStreamReader.SPACE) {
        type = reader.get().next();
      }
      if (type != expectType) {
        throw new XmpUnexpectedTypeException(message);
      }
    } catch (NoSuchElementException e) {
      // unexpected end of stream
      throw new XmpParsingException(
          "XMP Stream did not end in a good way, invalid content");
    }
  }

  /**
   * Check the next element type. White spaces , Comments and Processing
   * Instructions are ignored.
   *
   * @param type
   *            Type of xml element expected
   * @param message
   *            Error message if problems occur
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   */
  private void expectNextTag(int type, String message)
      throws XmpParsingException, XmpUnexpectedTypeException,
      XMLStreamException {
    try {
      if (!(reader.get().nextTag() == type)) {
        throw new XmpUnexpectedTypeException(message);
      }
    } catch (NoSuchElementException e) {
      // unexpected end of stream
      throw new XmpParsingException(
          "XMP Stream did not end in a good way, invalid content");
    }
  }

  /**
   * check if qualified name of current element is what is expected
   *
   * @param namespace
   *            namespace URI
   * @param name
   *            current element name
   * @throws XmpUnexpectedElementQualifiedNameException
   *             When a qualifiedName found and is not that expected
   *
   */
  private void expectName(String namespace, String name)
      throws XmpUnexpectedElementQualifiedNameException {
    if (!reader.get().getNamespaceURI().equals(namespace)) {
      throw new XmpUnexpectedElementQualifiedNameException("Expected '"
          + namespace + "' and found '"
          + reader.get().getNamespaceURI() + "'");
    }
    if (!reader.get().getLocalName().equals(name)) {
      throw new XmpUnexpectedElementQualifiedNameException("Expected '"
          + name + "' and found '" + reader.get().getLocalName()
          + "'");
    }
  }

  /**
   * Check the current element type.
   *
   * @param type
   *            XML element type expected
   * @param message
   *            Error Message if problems occur
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   */
  private void expectType(int type, String message)
      throws XmpUnexpectedTypeException {
    if (!(type == reader.get().getEventType())) {
      throw new XmpUnexpectedTypeException("Expected type " + type
          + " and found " + reader.get().getEventType() + " : "
          + message);
    }
  }

  /**
   * Check if rdf:about attribute is declared for rdf description and add all
   * attributes to the schema
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param schema
   *            Schema corresponding to the rdf:Description use
   * @throws XmpExpectedRdfAboutAttribute
   *             When rdf:Description not contains rdf:about attribute
   * @throws XmpUnexpectedTypeException if the attribute is known
   * as an expected property but the property type isn't a Simple type.
   */
  protected final void treatDescriptionAttributes(XMPMetadata metadata, XMPSchema schema)
      throws XmpExpectedRdfAboutAttribute, XmpUnexpectedTypeException {
    int cptAtt = reader.get().getAttributeCount();
    int i = 0;
    boolean rdfAboutFound = false;
    String prefix;
    while (i < cptAtt) {
      if (reader.get().getAttributeLocalName(i).equals("about")) {
        prefix = reader.get().getAttributePrefix(i);
        if (prefix != null) {
          if (!prefix.equals("") && !prefix.equals("rdf")) {
            // System.out.println("prefix de l'attribut "+reader.get().getAttributeLocalName(i)+": "+prefix);
            throw new XmpExpectedRdfAboutAttribute(
                "An about attribute is present but have an invalid prefix (it must be 'rdf')");
          }
        }
        rdfAboutFound = true;
      }

      Attribute attr = new Attribute(null, reader.get()
          .getAttributePrefix(i), reader.get()
          .getAttributeLocalName(i), reader.get()
          .getAttributeValue(i));

      if (!addAttributeAsProperty(metadata, schema, attr)) {
        // attribute isn't a property, so add the attribute
        schema.setAttribute(attr)
      }

      i++;
    }
    if (!rdfAboutFound) {
      // create rdf:about if not found
      Attribute attr = new Attribute(null,"rdf","about","");
      schema.setAttribute(attr);
    }
  }

  /**
   * If the attribute has same the name as an expected property of the Schema, then the property is created using the attributes fields.
   *
   * @param metadata Metadata to attach new elements
   * @param schema Schema corresponding to the rdf:Description use
   * @param attr the attribute used to create the property
   * @return true if the attribute has been converted into Property
   */
  private boolean addAttributeAsProperty(XMPMetadata metadata, XMPSchema schema, Attribute attr) {
    boolean added = false;
    String schemaNamespace = schema.getNamespaceValue();
    String prefix = attr.getPrefix() != null ? attr.getPrefix() : schema.getPrefix();
    String type = this.nsMap.getSpecifiedPropertyType(schemaNamespace, new QName(schemaNamespace, attr.getLocalName(), prefix));
    if (type != null) {
      if (type.equals("Text")) {
        schema.getContent().addProperty(new TextType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      } else if (type.equals("Integer")) {
        schema.getContent().addProperty(new IntegerType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      } else if (type.equals("Boolean")) {
        schema.getContent().addProperty(new BooleanType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      } else if (type.equals("Real")) {
        schema.getContent().addProperty(new RealType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      } else if (type.equals("Date")) {
        schema.getContent().addProperty(new DateType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      } else if (type.equals("URI")) {
        schema.getContent().addProperty(new TextType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      } else if (type.equals("URL")) {
        schema.getContent().addProperty(new TextType(metadata, prefix, attr.getLocalName(), attr.getValue()));
        added = true;
      }
    }
    return added;
  }

  /**
   * Treat each rdf:Description (which must represent a schema), instanciate
   * class representation of this schema and add it to metadata
   *
   * @param metadata
   *            Metadata to attach new elements
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpSchemaException
   *             When instancing schema object failed or in PDF/A Extension
   *             case, if its namespace miss
   * @throws XmpUnknownValueTypeException
   *             When ValueType found not correspond to basic type and not has
   *             been declared in current schema
   * @throws XmpExpectedRdfAboutAttribute
   *             When rdf:Description not contains rdf:about attribute
   * @throws BadFieldValueException
   *             When a bad value found in Schema description content
   */
  protected void parseDescription(XMPMetadata metadata)
      throws XmpParsingException, XMLStreamException, XmpSchemaException,
      XmpUnknownValueTypeException, XmpExpectedRdfAboutAttribute,
      BadFieldValueException {
    nsMap.resetComplexBasicTypesDeclarationInSchemaLevel();
    int cptNS = reader.get().getNamespaceCount();
    HashMap<String, String> namespaces = new HashMap<String, String>();
    for (int i = 0; i < cptNS; i++) {
      namespaces.put(reader.get().getNamespacePrefix(i), reader.get()
          .getNamespaceURI(i));
      if (nsMap.isComplexBasicTypes(reader.get().getNamespaceURI(i))) {
        // System.out.println("in parseDesc method: prefix:"+reader.get().getNamespacePrefix(i)+", nsURI:"+reader.get().getNamespaceURI(i));
        nsMap.setComplexBasicTypesDeclarationForLevelSchema(reader
            .get().getNamespaceURI(i), reader.get()
            .getNamespacePrefix(i));
      }
    }
    // Different treatment for PDF/A Extension schema
    // System.out.println(PDFAExtensionSchema.PDFAEXTENSION+";"+PDFAExtensionSchema.PDFAPROPERTY+";"+PDFAExtensionSchema.PDFASCHEMA);
    if (namespaces.containsKey(PDFAExtensionSchema.PDFAEXTENSION)) {
      if (namespaces.containsKey(PDFAExtensionSchema.PDFAPROPERTY)
          && namespaces.containsKey(PDFAExtensionSchema.PDFASCHEMA)) {
        if (namespaces
            .containsValue(PDFAExtensionSchema.PDFAEXTENSIONURI)
            && namespaces
            .containsValue(PDFAExtensionSchema.PDFAPROPERTYURI)
            && namespaces
            .containsValue(PDFAExtensionSchema.PDFASCHEMAURI)) {
          PDFAExtensionSchema schema = metadata
              .createAndAddPDFAExtensionSchemaWithNS(namespaces);
          treatDescriptionAttributes(metadata, schema);
          parseExtensionSchema(schema, metadata);

        } else {
          throw new XmpUnexpectedNamespaceURIException(
              "Unexpected namespaceURI in PDFA Extension Schema encountered");
        }
      } else {
        throw new XmpUnexpectedNamespacePrefixException(
            "Unexpected namespace Prefix in PDFA Extension Schema");
      }

    } else {
      int c = 0;
      String namespaceUri = reader.get().getNamespaceURI(c);
      String namespacePrefix = reader.get().getNamespacePrefix(c);
      c++;
      XMPSchema schema = nsMap.getAssociatedSchemaObject(metadata, namespaceUri, namespacePrefix);
      while (c<reader.get().getNamespaceCount() && schema==null) {
        // try next
        namespaceUri = reader.get().getNamespaceURI(c);
        namespacePrefix = reader.get().getNamespacePrefix(c);
        schema = nsMap.getAssociatedSchemaObject(metadata, namespaceUri, namespacePrefix);
        c++;
      }

      if (schema != null) {
        namespaces.remove(namespacePrefix);
      } else {
        schema = metadata.createAndAddDefaultSchema(namespacePrefix,namespaceUri);
      }

      for (int i = 1; i < cptNS; i++) {
        schema.setAttribute(new Attribute(XMPSchema.NS_NAMESPACE,
            "xmlns", reader.get().getNamespacePrefix(i), reader.get().getNamespaceURI(i)));
      }
      treatDescriptionAttributes(metadata, schema);
      while (reader.get().nextTag() == XMLStreamReader.START_ELEMENT) {
        parseProperty(schema, metadata);
      }
    }

  }

  /**
   * Check the next element type and its expected value
   *
   * @param type
   *            expected type of xml element
   * @param localNameExpected
   *            The property name (local) expected
   * @param message
   *            Error message if problems occur
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   */
  private void expectNextSpecificTag(int type, String localNameExpected,
      String message) throws XmpUnexpectedTypeException,
      XmpParsingException, XMLStreamException {
    expectNextTag(type, message);
    expectCurrentLocalName(localNameExpected);
  }

  /**
   * check that the current local name is that expected
   *
   * @param localNameExpected
   *            The name expected
   * @throws XmpUnexpectedElementException
   *             When Element is not that expected
   */
  protected void expectCurrentLocalName(String localNameExpected)
      throws XmpUnexpectedElementException {
    if (!reader.get().getLocalName().equals(localNameExpected)) {
      throw new XmpUnexpectedElementException("'" + localNameExpected
          + "' expected and '" + reader.get().getLocalName()
          + "' found at "+reader.get().getLocation());
    }
  }

  /**
   * Treat a PDFAExtension schema
   *
   * @param schema
   *            PDFA/Extension schema where save information found
   * @param metadata
   *            Metadata to attach new elements
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownValueTypeException
   *             When ValueType found not correspond to basic type and not has
   *             been declared in current schema
   * @throws BadFieldValueException
   *             When one of a field property include to describe a property
   *             in Schema Description contain an incorrect value
   */
  protected final void parseExtensionSchema(PDFAExtensionSchema schema,
      XMPMetadata metadata) throws XmpParsingException,
      XMLStreamException, XmpUnknownValueTypeException,
      BadFieldValueException {
    // <pdfaExtension:schemas>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, "schemas",
        "Cannot find container declaration of schemas descriptions ");
    // <rdf:Bag>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, BAG_NAME,
        "Cannot find bag declaration for container of schemas descriptions");
    // now work on each rdf:li corresponding to each schema description
    int type = reader.get().nextTag();
    while (type == XMLStreamReader.START_ELEMENT) {
      parseSchemaDescription(schema, metadata);
      type = reader.get().nextTag();
    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, "schemas",
        "Cannot find end of container declaration in schemas descriptions ");
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, "Description",
        "Cannot find end of PDF/A Extension definition ");

  }

  /**
   * Treat one Schema description defined in the extension Schema found
   *
   * @param schema
   *            PDFA/Extension schema where save information found
   * @param metadata
   *            Metadata to attach new elements
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XmpUnknownValueTypeException
   *             When ValueType found not correspond to basic type and not has
   *             been declared in current schema
   * @throws BadFieldValueException
   *             When one of a field property contain an incorrect value
   */
  private void parseSchemaDescription(PDFAExtensionSchema schema,
      XMPMetadata metadata) throws XMLStreamException,
      XmpParsingException, XmpUnknownValueTypeException,
      BadFieldValueException {
    expectCurrentLocalName("li");
    SchemaDescription desc = schema.createSchemaDescription();
    if ("Resource".equals(reader.get().getAttributeValue("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "parseType"))) {
      fillSchemaDescription(desc, metadata);
    } else {
      int type = reader.get().nextTag();
      if (type == XMLStreamReader.START_ELEMENT && reader.get().getLocalName().equals("Description")) {
        fillSchemaDescription(desc, metadata)
        // read the end tag
        reader.get().nextTag();
      } else {
        // ?? TODO
      }
    }

    schema.addSchemaDescription(desc);
    nsMap.setNamespaceDefinition(desc);

  }

  protected void fillSchemaDescription(SchemaDescription desc, XMPMetadata metadata)
      throws XMLStreamException, XmpParsingException,
      XmpUnknownValueTypeException, BadFieldValueException {
    int type = reader.get().nextTag();
    while (type == XMLStreamReader.START_ELEMENT) {
      if (reader.get().getLocalName().equals("schema")
          || reader.get().getLocalName().equals("namespaceURI")
          || reader.get().getLocalName().equals("prefix")) {
        try {
          // System.out.println(reader.get().getPrefix()+";"+reader.get().getLocalName()+";"+reader.get().getElementText());
          desc.addProperty(new TextType(metadata, reader.get()
              .getPrefix(), reader.get().getLocalName(), reader
              .get().getElementText()));
        } catch (IllegalArgumentException e) {
          throw new XmpPropertyFormatException(
              "Unexpected value for '"
                  + reader.get().getLocalName()
                  + "' property");
        }
      } else if (reader.get().getLocalName().equals("property")) {
        parsePropertyDefinition(desc);
      } else if (reader.get().getLocalName().equals(VALUE_TYPE_NAME)) {
        parseValueTypeDefinition(desc, metadata);
      } else {
        throw new XmpUnexpectedElementException(
            "Unexpected property definition in one of PDF/A Extension schemas description");
      }
      type = reader.get().nextTag();
    }
  }

  /**
   * Treat value type definition for a specific Schema Description
   *
   * @param desc
   *            the current Schema Description analyzed
   * @param metadata
   *            Metadata to attach new elements
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   */
  private void parseValueTypeDefinition(SchemaDescription desc,
      XMPMetadata metadata) throws XmpParsingException,
      XMLStreamException {
    // <rdf:Seq>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, SEQ_NAME,
        "Expected Seq Declaration");
    int elmtType = reader.get().nextTag();
    String type, namespaceURI, prefix, description;
    List<PDFAFieldDescription> fields;
    while (elmtType == XMLStreamReader.START_ELEMENT) {
      type = null;
      namespaceURI = null;
      prefix = null;
      description = null;
      fields = null;
      expectCurrentLocalName("li");
      elmtType = reader.get().nextTag();
      while (elmtType == XMLStreamReader.START_ELEMENT) {
        if (reader.get().getLocalName().equals("type")) {
          type = reader.get().getElementText();
        } else if (reader.get().getLocalName().equals("namespaceURI")) {
          namespaceURI = reader.get().getElementText();
        } else if (reader.get().getLocalName().equals("prefix")) {
          prefix = reader.get().getElementText();
        } else if (reader.get().getLocalName().equals("description")) {
          description = reader.get().getElementText();
        } else if (reader.get().getLocalName().equals("field")) {
          fields = parseFieldDescription(metadata);

        } else {
          throw new XmpUnexpectedElementException(
              "Unexpected property definition in one of ValueType Descriptions of PDF/A Extension schemas description");
        }
        elmtType = reader.get().nextTag();
      }
      if ((type != null) && (namespaceURI != null) && (prefix != null)
          && (description != null)) {
        desc.addValueType(type, namespaceURI, prefix, description,
            fields);
      } else {
        throw new XmpRequiredPropertyException(
            "one property declaration in PDF/A Extension is not complete");
      }
      elmtType = reader.get().nextTag();
    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, VALUE_TYPE_NAME,
        "Expected End of ValueType Declaration");

  }

  /**
   * Treat field description on the current analyzed value type description
   *
   * @param metadata
   *            Metadata to attach new elements
   * @return A list of parsed fields
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpParsingException
   *             When element expected not found
   */
  private List<PDFAFieldDescription> parseFieldDescription(
      XMPMetadata metadata) throws XmpParsingException,
      XMLStreamException {
    List<PDFAFieldDescription> fields = new ArrayList<PDFAFieldDescription>();
    // <rdf:Seq>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, SEQ_NAME,
        "Expected Seq Declaration");
    int elmtType = reader.get().nextTag();
    String name, type, description;
    while (elmtType == XMLStreamReader.START_ELEMENT) {
      expectCurrentLocalName("li");
      elmtType = reader.get().nextTag();
      name = null;
      type = null;
      description = null;

      while (elmtType == XMLStreamReader.START_ELEMENT) {
        if (reader.get().getLocalName().equals("name")) {
          name = reader.get().getElementText();
        } else if (reader.get().getLocalName().equals(VALUE_TYPE_NAME)) {
          type = reader.get().getElementText();
        } else if (reader.get().getLocalName().equals("description")) {
          description = reader.get().getElementText();
        } else {
          throw new XmpUnexpectedElementException(
              "Unexpected property definition in one of ValueType Field Descriptions of PDF/A Extension schemas description");
        }
        elmtType = reader.get().nextTag();
      }
      if ((name != null) && (type != null) && (description != null)) {
        PDFAFieldDescription tmp = new PDFAFieldDescription(metadata);
        tmp.setNameValue(name);
        tmp.setValueTypeValue(type);
        tmp.setDescriptionValue(description);
        fields.add(tmp);
      } else {
        throw new XmpRequiredPropertyException(
            "One valuetype field declaration in PDF/A Extension is not complete");
      }
      // expectNextTag(XMLStreamReader.END_ELEMENT,"Expected element end");
      elmtType = reader.get().nextTag();
    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, "field",
        "Expected End of Properties Declaration");
    if (fields.size() != 0) {
      return fields;
    }
    return null;
  }

  /**
   * Treat a property definition for a specific Schema Description
   *
   * @param desc
   *            the current Schema Description analyzed
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws BadFieldValueException
   *             When one of a field property contain an incorrect value
   */
  private void parsePropertyDefinition(SchemaDescription desc)
      throws XmpParsingException, XMLStreamException,  BadFieldValueException {
    // <rdf:Seq>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, SEQ_NAME, "Expected Seq Declaration");
    // Each property definition
    int elmtType = reader.get().nextTag();
    while (elmtType == XMLStreamReader.START_ELEMENT) {
      expectCurrentLocalName("li");
      if ("Resource".equals(reader.get().getAttributeValue("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "parseType"))) {
        fillDescription(desc);
      } else {
        elmtType = reader.get().nextTag();
        if (elmtType == XMLStreamReader.START_ELEMENT && reader.get().getLocalName().equals("Description")) {
          fillDescription(desc)
          // read the end tag
          reader.get().nextTag();
        } else {
          // ?? TODO
        }
      }
      // expectNextTag(XMLStreamReader.END_ELEMENT,"Expected element end");
      elmtType = reader.get().nextTag();
    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, "property",
        "Expected End of Properties Declaration");
  }

  protected void fillDescription(SchemaDescription desc)
      throws XmpParsingException, XMLStreamException,  BadFieldValueException {
    int elmtType = reader.get().nextTag();
    String name = null;
    String type = null;
    String category = null;
    String description = null;

    while (elmtType == XMLStreamReader.START_ELEMENT) {
      if (reader.get().getLocalName().equals("name")) {
        name = reader.get().getElementText();
      } else if (reader.get().getLocalName().equals(VALUE_TYPE_NAME)) {
        type = reader.get().getElementText();
      } else if (reader.get().getLocalName().equals("category")) {
        category = reader.get().getElementText();
      } else if (reader.get().getLocalName().equals("description")) {
        description = reader.get().getElementText();
      } else {
        throw new XmpUnexpectedElementException(
            "Unexpected property definition in one of Properties Descriptions of PDF/A Extension schemas description");
      }
      elmtType = reader.get().nextTag();
    }
    if ((name != null) && (type != null) && (category != null)&& (description != null)) {
      desc.addProperty(name, type, category, description);
    } else {
      throw new XmpRequiredPropertyException("one property declaration in PDF/A Extension is not complete");
    }
  }

  /**
   * Check for all namespaces declared for the specified schema if the
   * property searched exists and return its type or null
   *
   * @param schema
   *            The Schema to analyze
   * @param prop
   *            The property Qualified Name
   * @return The property value type or null if not found in schema
   * @throws XmpParsingException
   *             When element expected not found
   */
  private String getPropertyDeclarationInNamespaces(XMPSchema schema,
      QName prop) throws XmpParsingException {

    Iterator<Attribute> it = schema.getAllAttributes().iterator();
    Attribute tmp;
    ArrayList<Attribute> list = new ArrayList<Attribute>();
    while (it.hasNext()) {
      tmp = it.next();
      if (tmp.getPrefix() != null) {
        if (tmp.getPrefix().equals("xmlns")) {
          list.add(tmp);
        }
      }
    }
    it = list.iterator();
    String type;
    StringBuffer unknownNS = new StringBuffer();
    while (it.hasNext()) {
      String namespace = it.next().getValue();
      if (!nsMap.isContainedNamespace(namespace)) {
        unknownNS.append(" '").append(namespace).append("' ");
        continue;
      }
      type = nsMap.getSpecifiedPropertyType(namespace, prop);
      if (type != null) {
        return type;
      }
    }
    String uns = unknownNS.toString().trim();
    if ((uns == null) || "".equals(uns)) {
      throw new XmpUnknownPropertyException(
          "Cannot find a description for '" + prop.getLocalPart()
          + "' property");
    } else {
      throw new XmpUnknownSchemaException(
          "Cannot find a definition for the namespace " + uns + " ");
    }

  }

  /**
   * Build a property with the specific type defined in schema or complex
   * property and add it to the object representation
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param propertyName
   *            The fully qualified name of the property
   * @param stype
   *            Type of the property
   * @param container
   *            the entity where place the property representation
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   */
  protected void parseXmpSimpleProperty(XMPMetadata metadata,  QName propertyName, XmpPropertyType stype, ComplexPropertyContainer container
          throws XmpUnknownPropertyTypeException, XmpPropertyFormatException,  XMLStreamException {
    try {
      AbstractSimpleProperty prop = null;
      ArrayList<Attribute> attributes = new ArrayList<Attribute>();
      int cpt = reader.get().getAttributeCount();
      for (int i = 0; i < cpt; i++) {
        attributes.add(new Attribute(null, reader.get()
            .getAttributePrefix(i), reader.get()
            .getAttributeLocalName(i), reader.get()
            .getAttributeValue(i)));
      }
      if (stype == XmpPropertyType.Text) {
        prop = new TextType(metadata, propertyName.getPrefix(),
            propertyName.getLocalPart(), reader.get()
            .getElementText());
      } else if (stype == XmpPropertyType.Integer) {
        prop = new IntegerType(metadata, propertyName.getPrefix(),
            propertyName.getLocalPart(), reader.get()
            .getElementText());
      } else if (stype == XmpPropertyType.Date) {
        prop = new DateType(metadata, propertyName.getPrefix(),
            propertyName.getLocalPart(), reader.get()
            .getElementText());
      } else if (stype == XmpPropertyType.Boolean) {
        prop = new BooleanType(metadata, propertyName.getPrefix(),
            propertyName.getLocalPart(), reader.get()
            .getElementText());
      } else if (stype == XmpPropertyType.Real) {
        prop = new RealType(metadata, propertyName.getPrefix(),
            propertyName.getLocalPart(), reader.get()
            .getElementText());
      }
      if (prop != null) {
        container.addProperty(prop);
        // ADD ATTRIBUTES
        for (Attribute att : attributes) {
          prop.setAttribute(att);
        }
      } else {
        throw new XmpUnknownPropertyTypeException(
            "Unknown simple type found");
      }
    } catch (IllegalArgumentException e) {
      throw new XmpPropertyFormatException(
          "Unexpected type found for the property '"
              + propertyName.getLocalPart() + "'", e);
    }
  }

  /**
   * Parse a bag property (unordered array) with the specific type defined in
   * schema or complex property and add it to the object representation
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param bagName
   *            name of bag property
   * @param stype
   *            type of values contained in this bag
   * @param container
   *            the entity where place the property representation
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  protected void parseBagProperty(XMPMetadata metadata, QName bagName,
      XmpPropertyType stype, ComplexPropertyContainer container)
          throws XmpUnexpectedTypeException, XmpParsingException,
          XMLStreamException, XmpUnknownPropertyTypeException,
          XmpPropertyFormatException {
    ComplexProperty bag = new ComplexProperty(metadata,
        bagName.getPrefix(), bagName.getLocalPart(),
        ComplexProperty.UNORDERED_ARRAY);
    container.addProperty(bag);
    // <rdf:Bag>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, BAG_NAME, "Expected Bag Declaration");
    // Each property definition
    int elmtType = reader.get().nextTag();
    while ((elmtType != XMLStreamReader.END_ELEMENT)
        && !reader.get().getName().getLocalPart().equals(BAG_NAME)) {
      parseXmpSimpleProperty(metadata, reader.get().getName(), stype, bag.getContainer());
      elmtType = reader.get().nextTag();

    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, bagName
        .getLocalPart(), "Expected end of Bag property");

  }

  protected void parseComplexBagProperty(XMPMetadata metadata, QName bagName, StructuredPropertyParser complexParser,
      ComplexPropertyContainer container)
          throws XmpUnexpectedTypeException, XmpParsingException,
          XMLStreamException, XmpUnknownPropertyTypeException,
          XmpPropertyFormatException {
    ComplexProperty bag = new ComplexProperty(metadata,
        bagName.getPrefix(), bagName.getLocalPart(),
        ComplexProperty.UNORDERED_ARRAY);
    container.addProperty(bag);
    // <rdf:Bag>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, BAG_NAME,
        "Expected Bag Declaration");
    // Each property definition
    int elmtType = reader.get().nextTag();
    while ((elmtType != XMLStreamReader.END_ELEMENT)
        && !reader.get().getName().getLocalPart().equals(BAG_NAME)) {
      complexParser.parse(metadata, reader.get().getName(), bag.getContainer());
      elmtType = reader.get().nextTag();

    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, bagName
        .getLocalPart(), "Expected end of Bag property");

  }


  /**
   * Parse a seq property (ordered array) with the specific type defined in
   * schema or complex property and add it to the object representation
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param seqName
   *            name of the seq
   * @param stype
   *            type of values contained in this bag
   * @param container
   *            the entity where place the property representation
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  protected void parseSeqProperty(XMPMetadata metadata, QName seqName,
      XmpPropertyType stype, ComplexPropertyContainer container)
          throws XmpUnexpectedTypeException, XmpParsingException,
          XMLStreamException, XmpUnknownPropertyTypeException,
          XmpPropertyFormatException {
    ComplexProperty seq = new ComplexProperty(metadata,
        seqName.getPrefix(), seqName.getLocalPart(),
        ComplexProperty.ORDERED_ARRAY);
    container.addProperty(seq);
    // <rdf:Bag>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, SEQ_NAME,
        "Expected Seq Declaration");
    // Each property definition
    int elmtType = reader.get().nextTag();
    while ((elmtType != XMLStreamReader.END_ELEMENT)
        && !reader.get().getName().getLocalPart().equals(SEQ_NAME)) {
      parseXmpSimpleProperty(metadata, reader.get().getName(), stype, seq
          .getContainer());
      elmtType = reader.get().nextTag();

    }
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, seqName
        .getLocalPart(), "Expected end of Seq property");
  }

  /**
   * Parse Alt property (Alternative language property) with the specific type
   * defined in schema or complex property and add it to the object
   * representation
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param altName
   *            name of Alt property
   * @param stype
   *            type of values contained in this bag
   * @param container
   *            the entity where place the property representation
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  protected void parseAltProperty(XMPMetadata metadata, QName altName,
      XmpPropertyType stype, ComplexPropertyContainer container)
          throws XmpUnexpectedTypeException, XmpParsingException,
          XMLStreamException, XmpUnknownPropertyTypeException,
          XmpPropertyFormatException {
    ComplexProperty alt = new ComplexProperty(metadata,
        altName.getPrefix(), altName.getLocalPart(),
        ComplexProperty.ALTERNATIVE_ARRAY);
    container.addProperty(alt);
    // <rdf:Alt>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, ALT_NAME,
        "Expected Alt Declaration");
    int elmtType = reader.get().nextTag();
    while (!((elmtType == XMLStreamReader.END_ELEMENT) && reader.get()
        .getName().getLocalPart().equals(ALT_NAME))) {
      parseXmpSimpleProperty(metadata, reader.get().getName(), stype, alt
          .getContainer());
      elmtType = reader.get().nextTag();

    }
    // <dc:description><rdf:Alt><rdf:li>sujet</rdf:li></rdf:Alt></dc:description>
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, altName
        .getLocalPart(), "Expected end of alt property");

  }

  /**
   * Create a property in a specified container (complexproperty or schema)
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param type
   *            type of value contained in the property
   * @param container
   *            the entity where place the property representation
   * @return True if property has been treated (according to its type)
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   */
  private boolean createAndAddPropertyToContainer(XMPMetadata metadata,
      String type, ComplexPropertyContainer container)
          throws XmpParsingException, XmpUnexpectedTypeException,
          XmpUnknownPropertyTypeException, XmpPropertyFormatException,
          XMLStreamException {
    if (type.equals("Text")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else if (type.equals("Integer")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Integer, container);

    } else if (type.equals("Boolean")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Boolean, container);

    } else if (type.equals("Real")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Real, container);
    } else if (type.equals("Date")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Date, container);

    } else if (type.equals("URI")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);

    } else if (type.equals("URL")) {
      parseXmpSimpleProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);

    } else if (type.equals("bag Text")) {
      parseBagProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else if (type.equals("bag ProperName")) {
      parseBagProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else if (type.equals("bag Job")) {
      parseComplexBagProperty(metadata, reader.get().getName(), new JobParser(this), container);
    } else if (type.equals("bag Xpath")) {
      parseBagProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else if (type.equals("seq Text")) {
      parseSeqProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else if (type.equals("seq Field")) {
      parseSeqProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else if (type.equals("seq Date")) {
      parseSeqProperty(metadata, reader.get().getName(),
          XmpPropertyType.Date, container);
    } else if (type.equals("Lang Alt")) {
      parseAltProperty(metadata, reader.get().getName(),
          XmpPropertyType.Text, container);
    } else {
      return false;
    }
    return true;
  }

  /**
   * Parse a specific field
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param propertyName
   *            the full qualified name of this property
   * @param schema
   *            The schema where save this property
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  protected void parseFieldProperty(XMPMetadata metadata, QName propertyName,
      XMPSchema schema) throws XmpUnexpectedTypeException,
      XmpPropertyFormatException, XmpParsingException,
      XMLStreamException, XmpUnknownPropertyTypeException {
    ComplexPropertyContainer field = new ComplexPropertyContainer(metadata,
        propertyName.getPrefix(), propertyName.getLocalPart());
    schema.addProperty(field);
    field.setAttribute(new Attribute(null, "rdf", "parseType", "Resource"));
    String type;
    int elmtType = reader.get().nextTag();
    while ((elmtType != XMLStreamReader.END_ELEMENT)
        && !reader.get().getName().getLocalPart().equals(SEQ_NAME)) {

      type = getPropertyDeclarationInNamespaces(schema, reader.get()
          .getName());
      if (!createAndAddPropertyToContainer(metadata, type, field)) {
        if (type.equals("Field")) {
          String stype = getPropertyDeclarationInNamespaces(schema,
              reader.get().getName());
          createAndAddPropertyToContainer(metadata, stype, field);
        } else {
          throw new XmpUnknownPropertyTypeException("Unknown type : "
              + type);
        }
      }
      elmtType = reader.get().nextTag();
    }
    expectCurrentLocalName(propertyName.getLocalPart());

    // expectNextSpecificTag(XMLStreamReader.END_ELEMENT,
    // propertyName.getLocalPart(), "Expected end of field declaration");

  }

  /**
   * analyze one property in the stream, retrieve its type according to the
   * schema information and call its object representation building
   *
   * @param schema
   *            The schema where find information
   * @param metadata
   *            Metadata to attach new elements
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMPUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  protected void parseProperty(XMPSchema schema, XMPMetadata metadata)
      throws XmpParsingException, XmpPropertyFormatException,
      XmpUnexpectedTypeException, XMLStreamException,
      XmpUnknownPropertyTypeException {
    QName propertyName = reader.get().getName();
    nsMap.resetComplexBasicTypesDeclarationInPropertyLevel();
    int cptNs = reader.get().getNamespaceCount();
    for (int i = 0; i < cptNs; i++) {
      if (nsMap.isComplexBasicTypes(reader.get().getNamespaceURI(i))) {
        nsMap.setComplexBasicTypesDeclarationForLevelSchema(reader
            .get().getNamespaceURI(i), reader.get()
            .getNamespacePrefix(i));
      }
    }
    String type = getPropertyDeclarationInNamespaces(schema, propertyName);
    if (type.equals("Unmanaged")) {
      // do not parse the property, no validation, no reserialization
      boolean cont = true;
      while (cont) {
        int t = reader.get().next();
        if (t==XMLStreamReader.END_ELEMENT) {
          if (propertyName.equals(reader.get().getName())) {
            cont = false;
          }
        }
      }
    } else if (type.equals("Text")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Text, schema.getContent());

    } else if (type.equals("Integer")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Integer, schema.getContent());

    } else if (type.equals("Boolean")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Boolean, schema.getContent());

    } else if (type.equals("Real")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Real, schema.getContent());
    } else if (type.equals("Date")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Date, schema.getContent());

    } else if (type.equals("URI")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Text, schema.getContent());

    } else if (type.equals("URL")) {
      parseXmpSimpleProperty(metadata, propertyName,
          XmpPropertyType.Text, schema.getContent());

    } else if (type.equals("bag Text")) {
      parseBagProperty(metadata, propertyName, XmpPropertyType.Text,
          schema.getContent());
    } else if (type.equals("bag ProperName")) {
      parseBagProperty(metadata, propertyName, XmpPropertyType.Text,
          schema.getContent());
    } else if (type.equals("bag Job")) {
      parseComplexBagProperty(metadata, propertyName, new JobParser(this), schema.getContent());
    } else if (type.equals("bag Xpath")) {
      parseBagProperty(metadata, propertyName, XmpPropertyType.Text,
          schema.getContent());
    } else if (type.equals("seq Text")) {
      parseSeqProperty(metadata, propertyName, XmpPropertyType.Text,
          schema.getContent());
    } else if (type.equals("seq Date")) {
      parseSeqProperty(metadata, propertyName, XmpPropertyType.Date,
          schema.getContent());
    } else if (type.equals("Lang Alt")) {
      parseAltProperty(metadata, propertyName, XmpPropertyType.Text,
          schema.getContent());
    } else if (type.equals("Field")) {
      parseFieldProperty(metadata, propertyName, schema);
    } else if (type.equals("Thumbnail")) {
      parseThumbnailProperty(metadata, propertyName, schema.getContent());
    } else if (type.equals("Alt Thumbnail")) {
      parseAltThumbnailProperty(metadata, propertyName, schema
          .getContent());
    } else {
      throw new XmpUnknownPropertyTypeException("Unknown type : " + type);
    }

  }

  /**
   * Treat Alternative Thumbnails property
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param altName
   *            name of thumbnails alternative property
   * @param container
   *            the container where record this representation
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  private void parseAltThumbnailProperty(XMPMetadata metadata, QName altName,
      ComplexPropertyContainer container)
          throws XmpUnexpectedTypeException, XmpParsingException,
          XMLStreamException, XmpUnknownPropertyTypeException,
          XmpPropertyFormatException {
    ComplexProperty alt = new ComplexProperty(metadata,
        altName.getPrefix(), altName.getLocalPart(),
        ComplexProperty.ALTERNATIVE_ARRAY);
    container.addProperty(alt);
    // <rdf:Alt>
    expectNextSpecificTag(XMLStreamReader.START_ELEMENT, ALT_NAME,
        "Expected Alt Declaration");
    int elmtType = reader.get().nextTag();
    while (!((elmtType == XMLStreamReader.END_ELEMENT) && reader.get()
        .getName().getLocalPart().equals(ALT_NAME))) {
      parseThumbnailProperty(metadata, reader.get().getName(), alt
          .getContainer());
      elmtType = reader.get().nextTag();
    }

    // <dc:description><rdf:Alt><rdf:li>sujet</rdf:li></rdf:Alt></dc:description>
    expectNextSpecificTag(XMLStreamReader.END_ELEMENT, altName
        .getLocalPart(), "Expected end of alt property");
  }

  /**
   * * Treat a thumbnail property
   *
   * @param metadata
   *            Metadata to attach new elements
   * @param altName
   *            name of thumbnail property
   * @param container
   *            The container where save property representation
   * @throws XmpUnexpectedTypeException
   *             When DOM Element type found unexpected
   * @throws XmpParsingException
   *             When element expected not found
   * @throws XMLStreamException
   *             When error during reading the rest of xmp stream
   * @throws XmpUnknownPropertyTypeException
   *             Value Type property is incorrect or the basic value type
   *             can't be treat at the moment
   * @throws XmpPropertyFormatException
   *             Unexpected type found (IllegalArgumentException)
   */
  private void parseThumbnailProperty(XMPMetadata metadata, QName altName,
      ComplexPropertyContainer container)
          throws XmpUnexpectedTypeException, XmpParsingException,
          XMLStreamException, XmpUnknownPropertyTypeException,
          XmpPropertyFormatException {
    expectCurrentLocalName("li");
    ThumbnailType thumbnail = new ThumbnailType(metadata, altName
        .getPrefix(), altName.getLocalPart());
    int elmtType = reader.get().nextTag();
    QName eltName;
    String eltContent;
    while (!((elmtType == XMLStreamReader.END_ELEMENT) && reader.get()
        .getName().getLocalPart().equals("li"))) {
      eltName = reader.get().getName();
      eltContent = reader.get().getElementText();
      if (eltName.getLocalPart().equals("height")) {
        thumbnail.setHeight(eltName.getPrefix(),
            eltName.getLocalPart(), Integer.valueOf(eltContent));
      } else if (eltName.getLocalPart().equals("width")) {
        thumbnail.setWidth(eltName.getPrefix(), eltName.getLocalPart(),
            Integer.valueOf(eltContent));
      } else if (eltName.getLocalPart().equals("image")) {
        thumbnail.setImg(eltName.getPrefix(), eltName.getLocalPart(),
            eltContent);
      } else if (eltName.getLocalPart().equals("format")) {
        thumbnail.setFormat(eltName.getPrefix(),
            eltName.getLocalPart(), eltContent);
      } else {
        throw new XmpParsingException(
            "Unknown property name for a thumbnail element : "
                + eltName.getLocalPart());
      }
      elmtType = reader.get().nextTag();
    }
    container.addProperty(thumbnail);
  }




}
TOP

Related Classes of org.apache.padaf.xmpbox.parser.XMPDocumentBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.