blob: 12f7159d430a8a5fdbfa6f9e8cd3f872193bc898 [file] [log] [blame]
/*
* 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.
*/
/* $Id$ */
package org.apache.xmlgraphics.xmp;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* Represents an XMP array as defined by the XMP specification.
*/
public class XMPArray extends XMPComplexValue {
//TODO Property qualifiers are currently not supported, yet.
private XMPArrayType type;
private List values = new java.util.ArrayList();
private List xmllang = new java.util.ArrayList();
private List<String> parseTypes = new ArrayList<>();
/**
* Main constructor
* @param type the intended type of array
*/
public XMPArray(XMPArrayType type) {
this.type = type;
}
/** @return the type of array */
public XMPArrayType getType() {
return this.type;
}
/**
* Returns the value at a given position.
* @param idx the index of the requested value
* @return the value at the given position
*/
public Object getValue(int idx) {
return this.values.get(idx);
}
/**
* Returns the structure at a given position. If the value is not a structure a
* ClassCastException is thrown.
* @param idx the index of the requested value
* @return the structure at the given position
*/
public XMPStructure getStructure(int idx) {
return (XMPStructure)this.values.get(idx);
}
/** {@inheritDoc} */
public Object getSimpleValue() {
if (values.size() == 1) {
return getValue(0);
} else if (values.size() > 1) {
return getLangValue(XMPConstants.DEFAULT_LANGUAGE);
} else {
return null;
}
}
private String getParentLanguage(String lang) {
if (lang == null) {
return null;
}
int pos = lang.indexOf('-');
if (pos > 0) {
String parent = lang.substring(0, pos);
return parent;
}
return null;
}
/**
* Returns a language-dependent values (available for alternative arrays).
* @param lang the language ("x-default" for the default value)
* @return the requested value
*/
public String getLangValue(String lang) {
String v = null;
String valueForParentLanguage = null;
for (int i = 0, c = values.size(); i < c; i++) {
String l = (String)xmllang.get(i);
if ((l == null && lang == null) || (l != null && l.equals(lang))) {
v = values.get(i).toString();
break;
}
if (l != null && lang != null) {
//Check for "parent" language, too ("en" matches "en-GB")
String parent = getParentLanguage(l);
if (parent != null && parent.equals(lang)) {
valueForParentLanguage = values.get(i).toString();
}
}
}
if (lang != null && v == null && valueForParentLanguage != null) {
//Use value found for parent language
v = valueForParentLanguage;
}
if (lang == null && v == null) {
v = getLangValue(XMPConstants.DEFAULT_LANGUAGE);
if (v == null && values.size() > 0) {
v = getValue(0).toString(); //get first
}
}
return v;
}
/**
* Removes a language-dependent value.
* @param lang the language ("x-default" for the default value)
* @return the removed value (or null if no value was set)
*/
public String removeLangValue(String lang) {
if (lang == null || "".equals(lang)) {
lang = XMPConstants.DEFAULT_LANGUAGE;
}
for (int i = 0, c = values.size(); i < c; i++) {
String l = (String)xmllang.get(i);
if ((XMPConstants.DEFAULT_LANGUAGE.equals(lang) && l == null) || lang.equals(l)) {
String value = (String)values.remove(i);
xmllang.remove(i);
return value;
}
}
return null;
}
/**
* Adds a new value to the array
* @param value the value
*/
public void add(Object value, String lang, String parseType) {
values.add(value);
xmllang.add(lang);
parseTypes.add(parseType);
}
/**
* Adds a language-dependent value to the array. Make sure not to add the same language twice.
* @param value the value
* @param lang the language ("x-default" for the default value)
*/
public void add(Object value, String lang) {
add(value, lang, null);
}
public void add(Object value) {
add(value, null, null);
}
/**
* Removes a value from the array. If the value doesn't exist, nothing happens.
* @param value the value to be removed
* @return true if the value was removed, false if it wasn't found
*/
public boolean remove(String value) {
int idx = values.indexOf(value);
if (idx >= 0) {
values.remove(idx);
xmllang.remove(idx);
parseTypes.remove(idx);
return true;
}
return false;
}
/**
* Returns the current number of values in the array.
* @return the current number of values in the array
*/
public int getSize() {
return this.values.size();
}
/**
* Indicates whether the array is empty or not.
* @return true if the array is empty
*/
public boolean isEmpty() {
return getSize() == 0;
}
/**
* Converts the array to an object array.
* @return an object array of all values in the array
*/
public Object[] toObjectArray() {
Object[] res = new Object[getSize()];
for (int i = 0, c = res.length; i < c; i++) {
res[i] = getValue(i);
}
return res;
}
/** {@inheritDoc} */
public void toSAX(ContentHandler handler) throws SAXException {
AttributesImpl atts = new AttributesImpl();
handler.startElement(XMPConstants.RDF_NAMESPACE,
type.getName(), "rdf:" + type.getName(), atts);
for (int i = 0, c = values.size(); i < c; i++) {
String lang = (String)xmllang.get(i);
atts.clear();
Object v = values.get(i);
if (lang != null) {
atts.addAttribute(XMPConstants.XML_NS, "lang", "xml:lang", "CDATA", lang);
}
if (v instanceof URI) {
atts.addAttribute(XMPConstants.RDF_NAMESPACE, "resource",
"rdf:resource", "CDATA", ((URI)v).toString());
}
String parseType = parseTypes.get(i);
if (parseType != null) {
atts.addAttribute(XMPConstants.RDF_NAMESPACE, "parseType", "rdf:parseType", "CDATA", parseType);
}
handler.startElement(XMPConstants.RDF_NAMESPACE,
"li", "rdf:li", atts);
if (v instanceof XMPComplexValue) {
((XMPComplexValue)v).toSAX(handler);
} else if (v instanceof XMPProperty) {
XMPProperty prop = (XMPProperty) v;
prop.toSAX(handler);
} else if (v instanceof List) {
List<XMPProperty> list = (List<XMPProperty>) v;
for (XMPProperty prop : list) {
prop.toSAX(handler);
}
} else if (!(v instanceof URI)) {
String value = (String)values.get(i);
char[] chars = value.toCharArray();
handler.characters(chars, 0, chars.length);
}
handler.endElement(XMPConstants.RDF_NAMESPACE,
"li", "rdf:li");
}
handler.endElement(XMPConstants.RDF_NAMESPACE,
type.getName(), "rdf:" + type.getName());
}
/** {@inheritDoc} */
public String toString() {
return "XMP array: " + type + ", " + getSize();
}
}