📄 xmpnode.java
字号:
//=================================================================================================// ADOBE SYSTEMS INCORPORATED// Copyright 2006-2007 Adobe Systems Incorporated// All Rights Reserved//// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms// of the Adobe license agreement accompanying it.// =================================================================================================package com.adobe.xmp.impl;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.Iterator;import java.util.List;import java.util.ListIterator;import com.adobe.xmp.XMPConst;import com.adobe.xmp.XMPError;import com.adobe.xmp.XMPException;import com.adobe.xmp.options.PropertyOptions;/** * A node in the internally XMP tree, which can be a schema node, a property node, an array node, * an array item, a struct node or a qualifier node (without '?'). * * Possible improvements: * * 1. The kind Node of node might be better represented by a class-hierarchy of different nodes. * 2. The array type should be an enum * 3. isImplicitNode should be removed completely and replaced by return values of fi. * 4. hasLanguage, hasType should be automatically maintained by XMPNode * * @since 21.02.2006 */class XMPNode implements Comparable{ /** name of the node, contains different information depending of the node kind */ private String name; /** value of the node, contains different information depending of the node kind */ private String value; /** link to the parent node */ private XMPNode parent; /** list of child nodes, lazy initialized */ private List children = null; /** list of qualifier of the node, lazy initialized */ private List qualifier = null; /** options describing the kind of the node */ private PropertyOptions options = null; // internal processing options /** flag if the node is implicitly created */ private boolean implicit; /** flag if the node has aliases */ private boolean hasAliases; /** flag if the node is an alias */ private boolean alias; /** flag if the node has an "rdf:value" child node. */ private boolean hasValueChild; /** * Creates an <code>XMPNode</code> with initial values. * * @param name the name of the node * @param value the value of the node * @param options the options of the node */ public XMPNode(String name, String value, PropertyOptions options) { this.name = name; this.value = value; this.options = options; } /** * Constructor for the node without value. * * @param name the name of the node * @param options the options of the node */ public XMPNode(String name, PropertyOptions options) { this(name, null, options); } /** * Resets the node. */ public void clear() { options = null; name = null; value = null; children = null; qualifier = null; } /** * @return Returns the parent node. */ public XMPNode getParent() { return parent; } /** * @param index an index [1..size] * @return Returns the child with the requested index. */ public XMPNode getChild(int index) { return (XMPNode) getChildren().get(index - 1); } /** * Adds a node as child to this node. * @param node an XMPNode * @throws XMPException */ public void addChild(XMPNode node) throws XMPException { // check for duplicate properties assertChildNotExisting(node.getName()); node.setParent(this); getChildren().add(node); } /** * Adds a node as child to this node. * @param index the index of the node <em>before</em> which the new one is inserted. * <em>Note:</em> The node children are indexed from [1..size]! * An index of size + 1 appends a node. * @param node an XMPNode * @throws XMPException */ public void addChild(int index, XMPNode node) throws XMPException { assertChildNotExisting(node.getName()); node.setParent(this); getChildren().add(index - 1, node); } /** * Replaces a node with another one. * @param index the index of the node that will be replaced. * <em>Note:</em> The node children are indexed from [1..size]! * @param node the replacement XMPNode */ public void replaceChild(int index, XMPNode node) { node.setParent(this); getChildren().set(index - 1, node); } /** * Removes a child at the requested index. * @param itemIndex the index to remove [1..size] */ public void removeChild(int itemIndex) { getChildren().remove(itemIndex - 1); cleanupChildren(); } /** * Removes a child node. * If its a schema node and doesn't have any children anymore, its deleted. * * @param node the child node to delete. */ public void removeChild(XMPNode node) { getChildren().remove(node); cleanupChildren(); } /** * Removes the children list if this node has no children anymore; * checks if the provided node is a schema node and doesn't have any children anymore, * its deleted. */ protected void cleanupChildren() { if (children.isEmpty()) { children = null; } } /** * Removes all children from the node. */ public void removeChildren() { children = null; } /** * @return Returns the number of children without neccessarily creating a list. */ public int getChildrenLength() { return children != null ? children.size() : 0; } /** * @param expr child node name to look for * @return Returns an <code>XMPNode</code> if node has been found, <code>null</code> otherwise. */ public XMPNode findChildByName(String expr) { return find(getChildren(), expr); } /** * @param index an index [1..size] * @return Returns the qualifier with the requested index. */ public XMPNode getQualifier(int index) { return (XMPNode) getQualifier().get(index - 1); } /** * @return Returns the number of qualifier without neccessarily creating a list. */ public int getQualifierLength() { return qualifier != null ? qualifier.size() : 0; } /** * Appends a qualifier to the qualifier list and sets respective options. * @param qualNode a qualifier node. * @throws XMPException */ public void addQualifier(XMPNode qualNode) throws XMPException { assertQualifierNotExisting(qualNode.getName()); qualNode.setParent(this); qualNode.getOptions().setQualifier(true); getOptions().setHasQualifiers(true); // contraints if (qualNode.isLanguageNode()) { // "xml:lang" is always first and the option "hasLanguage" is set options.setHasLanguage(true); getQualifier().add(0, qualNode); } else if (qualNode.isTypeNode()) { // "rdf:type" must be first or second after "xml:lang" and the option "hasType" is set options.setHasType(true); getQualifier().add( !options.getHasLanguage() ? 0 : 1, qualNode); } else { // other qualifiers are appended getQualifier().add(qualNode); } } /** * Removes one qualifier node and fixes the options. * @param qualNode qualifier to remove */ public void removeQualifier(XMPNode qualNode) { PropertyOptions opts = getOptions(); if (qualNode.isLanguageNode()) { // if "xml:lang" is removed, remove hasLanguage-flag too opts.setHasLanguage(false); } else if (qualNode.isTypeNode()) { // if "rdf:type" is removed, remove hasType-flag too opts.setHasType(false); } getQualifier().remove(qualNode); if (qualifier.isEmpty()) { opts.setHasQualifiers(false); qualifier = null; } } /** * Removes all qualifiers from the node and sets the options appropriate. */ public void removeQualifiers() { PropertyOptions opts = getOptions(); // clear qualifier related options opts.setHasQualifiers(false); opts.setHasLanguage(false); opts.setHasType(false); qualifier = null; } /** * @param expr qualifier node name to look for * @return Returns a qualifier <code>XMPNode</code> if node has been found, * <code>null</code> otherwise. */ public XMPNode findQualifierByName(String expr) { return find(qualifier, expr); } /** * @return Returns whether the node has children. */ public boolean hasChildren() { return children != null && children.size() > 0; } /** * @return Returns an iterator for the children. * <em>Note:</em> take care to use it.remove(), as the flag are not adjusted in that case. */ public Iterator iterateChildren() { if (children != null) { return getChildren().iterator(); } else { return Collections.EMPTY_LIST.listIterator(); } } /** * @return Returns whether the node has qualifier attached. */ public boolean hasQualifier() { return qualifier != null && qualifier.size() > 0; } /** * @return Returns an iterator for the qualifier. * <em>Note:</em> take care to use it.remove(), as the flag are not adjusted in that case. */ public Iterator iterateQualifier() { if (qualifier != null) { final Iterator it = getQualifier().iterator(); return new Iterator() { public boolean hasNext() { return it.hasNext(); } public Object next() { return it.next(); } public void remove() { throw new UnsupportedOperationException( "remove() is not allowed due to the internal contraints"); } }; } else { return Collections.EMPTY_LIST.iterator(); } } /** * Performs a <b>deep clone</b> of the node and the complete subtree. * * @see java.lang.Object#clone() */ public Object clone() { PropertyOptions newOptions; try { newOptions = new PropertyOptions(getOptions().getOptions()); } catch (XMPException e) { // cannot happen newOptions = new PropertyOptions(); } XMPNode newNode = new XMPNode(name, value, newOptions); cloneSubtree(newNode); return newNode; } /** * Performs a <b>deep clone</b> of the complete subtree (children and * qualifier )into and add it to the destination node. * * @param destination the node to add the cloned subtree */ public void cloneSubtree(XMPNode destination) { try { for (Iterator it = iterateChildren(); it.hasNext();) { XMPNode child = (XMPNode) it.next(); destination.addChild((XMPNode) child.clone()); } for (Iterator it = iterateQualifier(); it.hasNext();) { XMPNode qualifier = (XMPNode) it.next(); destination.addQualifier((XMPNode) qualifier.clone());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -