org.mozilla.javascript.xmlimpl.XMLName Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino-runtime Show documentation
Show all versions of rhino-runtime Show documentation
Rhino JavaScript runtime jar, excludes tools & JSR-223 Script Engine wrapper.
The newest version!
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript.xmlimpl;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.Kit;
import org.mozilla.javascript.Ref;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Undefined;
class XMLName extends Ref {
static final long serialVersionUID = 3832176310755686977L;
private static boolean isNCNameStartChar(int c) {
if ((c & ~0x7F) == 0) {
// Optimize for ASCII and use A..Z < _ < a..z
if (c >= 'a') {
return c <= 'z';
} else if (c >= 'A') {
if (c <= 'Z') {
return true;
}
return c == '_';
}
} else if ((c & ~0x1FFF) == 0) {
return (0xC0 <= c && c <= 0xD6)
|| (0xD8 <= c && c <= 0xF6)
|| (0xF8 <= c && c <= 0x2FF)
|| (0x370 <= c && c <= 0x37D)
|| 0x37F <= c;
}
return (0x200C <= c && c <= 0x200D)
|| (0x2070 <= c && c <= 0x218F)
|| (0x2C00 <= c && c <= 0x2FEF)
|| (0x3001 <= c && c <= 0xD7FF)
|| (0xF900 <= c && c <= 0xFDCF)
|| (0xFDF0 <= c && c <= 0xFFFD)
|| (0x10000 <= c && c <= 0xEFFFF);
}
private static boolean isNCNameChar(int c) {
if ((c & ~0x7F) == 0) {
// Optimize for ASCII and use - < . < 0..9 < A..Z < _ < a..z
if (c >= 'a') {
return c <= 'z';
} else if (c >= 'A') {
if (c <= 'Z') {
return true;
}
return c == '_';
} else if (c >= '0') {
return c <= '9';
} else {
return c == '-' || c == '.';
}
} else if ((c & ~0x1FFF) == 0) {
return isNCNameStartChar(c) || c == 0xB7 || (0x300 <= c && c <= 0x36F);
}
return isNCNameStartChar(c) || (0x203F <= c && c <= 0x2040);
}
// This means "accept" in the parsing sense
// See ECMA357 13.1.2.1
static boolean accept(Object nameObj) {
String name;
try {
name = ScriptRuntime.toString(nameObj);
} catch (EcmaError ee) {
if ("TypeError".equals(ee.getName())) {
return false;
}
throw ee;
}
// See http://w3.org/TR/xml-names11/#NT-NCName
int length = name.length();
if (length != 0) {
if (isNCNameStartChar(name.charAt(0))) {
for (int i = 1; i != length; ++i) {
if (!isNCNameChar(name.charAt(i))) {
return false;
}
}
return true;
}
}
return false;
}
private XmlNode.QName qname;
private boolean isAttributeName;
private boolean isDescendants;
private XMLObjectImpl xmlObject;
private XMLName() {}
static XMLName formStar() {
XMLName rv = new XMLName();
rv.qname = XmlNode.QName.create(null, null);
return rv;
}
/** @deprecated */
@Deprecated
static XMLName formProperty(XmlNode.Namespace namespace, String localName) {
if (localName != null && localName.equals("*")) localName = null;
XMLName rv = new XMLName();
rv.qname = XmlNode.QName.create(namespace, localName);
return rv;
}
/** TODO: marked deprecated by original author */
static XMLName formProperty(String uri, String localName) {
return formProperty(XmlNode.Namespace.create(uri), localName);
}
/** TODO: marked deprecated by original implementor */
static XMLName create(String defaultNamespaceUri, String name) {
if (name == null) throw new IllegalArgumentException();
int l = name.length();
if (l != 0) {
char firstChar = name.charAt(0);
if (firstChar == '*') {
if (l == 1) {
return XMLName.formStar();
}
} else if (firstChar == '@') {
XMLName xmlName = XMLName.formProperty("", name.substring(1));
xmlName.setAttributeName();
return xmlName;
}
}
return XMLName.formProperty(defaultNamespaceUri, name);
}
static XMLName create(XmlNode.QName qname, boolean attribute, boolean descendants) {
XMLName rv = new XMLName();
rv.qname = qname;
rv.isAttributeName = attribute;
rv.isDescendants = descendants;
return rv;
}
/** @deprecated */
@Deprecated
static XMLName create(XmlNode.QName qname) {
return create(qname, false, false);
}
void initXMLObject(XMLObjectImpl xmlObject) {
if (xmlObject == null) throw new IllegalArgumentException();
if (this.xmlObject != null) throw new IllegalStateException();
this.xmlObject = xmlObject;
}
String uri() {
if (qname.getNamespace() == null) return null;
return qname.getNamespace().getUri();
}
String localName() {
if (qname.getLocalName() == null) return "*";
return qname.getLocalName();
}
private void addDescendantChildren(XMLList list, XML target) {
XMLName xmlName = this;
if (target.isElement()) {
XML[] children = target.getChildren();
for (int i = 0; i < children.length; i++) {
if (xmlName.matches(children[i])) {
list.addToList(children[i]);
}
addDescendantChildren(list, children[i]);
}
}
}
void addMatchingAttributes(XMLList list, XML target) {
XMLName name = this;
if (target.isElement()) {
XML[] attributes = target.getAttributes();
for (int i = 0; i < attributes.length; i++) {
if (name.matches(attributes[i])) {
list.addToList(attributes[i]);
}
}
}
}
private void addDescendantAttributes(XMLList list, XML target) {
if (target.isElement()) {
addMatchingAttributes(list, target);
XML[] children = target.getChildren();
for (int i = 0; i < children.length; i++) {
addDescendantAttributes(list, children[i]);
}
}
}
XMLList matchDescendantAttributes(XMLList rv, XML target) {
rv.setTargets(target, null);
addDescendantAttributes(rv, target);
return rv;
}
XMLList matchDescendantChildren(XMLList rv, XML target) {
rv.setTargets(target, null);
addDescendantChildren(rv, target);
return rv;
}
void addDescendants(XMLList rv, XML target) {
XMLName xmlName = this;
if (xmlName.isAttributeName()) {
matchDescendantAttributes(rv, target);
} else {
matchDescendantChildren(rv, target);
}
}
private void addAttributes(XMLList rv, XML target) {
addMatchingAttributes(rv, target);
}
void addMatches(XMLList rv, XML target) {
if (isDescendants()) {
addDescendants(rv, target);
} else if (isAttributeName()) {
addAttributes(rv, target);
} else {
XML[] children = target.getChildren();
if (children != null) {
for (int i = 0; i < children.length; i++) {
if (this.matches(children[i])) {
rv.addToList(children[i]);
}
}
}
rv.setTargets(target, this.toQname());
}
}
XMLList getMyValueOn(XML target) {
XMLList rv = target.newXMLList();
addMatches(rv, target);
return rv;
}
void setMyValueOn(XML target, Object value) {
// Special-case checks for undefined and null
if (value == null) {
value = "null";
} else if (value instanceof Undefined) {
value = "undefined";
}
XMLName xmlName = this;
// Get the named property
if (xmlName.isAttributeName()) {
target.setAttribute(xmlName, value);
} else if (xmlName.uri() == null && xmlName.localName().equals("*")) {
target.setChildren(value);
} else {
// Convert text into XML if needed.
XMLObjectImpl xmlValue = null;
if (value instanceof XMLObjectImpl) {
xmlValue = (XMLObjectImpl) value;
// Check for attribute type and convert to textNode
if (xmlValue instanceof XML) {
if (((XML) xmlValue).isAttribute()) {
xmlValue = target.makeXmlFromString(xmlName, xmlValue.toString());
}
}
if (xmlValue instanceof XMLList) {
for (int i = 0; i < xmlValue.length(); i++) {
XML xml = ((XMLList) xmlValue).item(i);
if (xml.isAttribute()) {
((XMLList) xmlValue)
.replace(i, target.makeXmlFromString(xmlName, xml.toString()));
}
}
}
} else {
xmlValue = target.makeXmlFromString(xmlName, ScriptRuntime.toString(value));
}
XMLList matches = target.getPropertyList(xmlName);
if (matches.length() == 0) {
target.appendChild(xmlValue);
} else {
// Remove all other matches
for (int i = 1; i < matches.length(); i++) {
target.removeChild(matches.item(i).childIndex());
}
// Replace first match with new value.
XML firstMatch = matches.item(0);
target.replace(firstMatch.childIndex(), xmlValue);
}
}
}
@Override
public boolean has(Context cx) {
if (xmlObject == null) {
return false;
}
return xmlObject.hasXMLProperty(this);
}
@Override
public Object get(Context cx) {
if (xmlObject == null) {
throw ScriptRuntime.undefReadError(Undefined.instance, toString());
}
return xmlObject.getXMLProperty(this);
}
@SuppressWarnings("deprecation")
@Override
public Object set(Context cx, Object value) {
if (xmlObject == null) {
throw ScriptRuntime.undefWriteError(Undefined.instance, toString(), value);
}
// Assignment to descendants causes parse error on bad reference
// and this should not be called
if (isDescendants) throw Kit.codeBug();
xmlObject.putXMLProperty(this, value);
return value;
}
@Override
public boolean delete(Context cx) {
if (xmlObject == null) {
return true;
}
xmlObject.deleteXMLProperty(this);
return !xmlObject.hasXMLProperty(this);
}
@Override
public String toString() {
// return qname.localName();
StringBuilder buff = new StringBuilder();
if (isDescendants) buff.append("..");
if (isAttributeName) buff.append('@');
if (uri() == null) {
buff.append('*');
if (localName().equals("*")) {
return buff.toString();
}
} else {
buff.append('"').append(uri()).append('"');
}
buff.append(':').append(localName());
return buff.toString();
}
final XmlNode.QName toQname() {
return this.qname;
}
final boolean matchesLocalName(String localName) {
return localName().equals("*") || localName().equals(localName);
}
final boolean matchesElement(XmlNode.QName qname) {
if (this.uri() == null || this.uri().equals(qname.getNamespace().getUri())) {
if (this.localName().equals("*") || this.localName().equals(qname.getLocalName())) {
return true;
}
}
return false;
}
final boolean matches(XML node) {
XmlNode.QName qname = node.getNodeQname();
String nodeUri = null;
if (qname.getNamespace() != null) {
nodeUri = qname.getNamespace().getUri();
}
if (isAttributeName) {
if (node.isAttribute()) {
if (this.uri() == null || this.uri().equals(nodeUri)) {
if (this.localName().equals("*")
|| this.localName().equals(qname.getLocalName())) {
return true;
}
}
return false;
} else {
// TODO Could throw exception maybe, should not call this method on attribute
// name with arbitrary node type
// unless we traverse all attributes and children habitually
return false;
}
} else {
if (this.uri() == null || ((node.isElement()) && this.uri().equals(nodeUri))) {
if (localName().equals("*")) return true;
if (node.isElement()) {
if (localName().equals(qname.getLocalName())) return true;
}
}
return false;
}
}
/* TODO: marked deprecated by original author */
boolean isAttributeName() {
return isAttributeName;
}
// TODO Fix whether this is an attribute XMLName at construction?
// Marked deprecated by original author
void setAttributeName() {
// if (isAttributeName) throw new IllegalStateException();
isAttributeName = true;
}
/* TODO: was marked deprecated by original author */
boolean isDescendants() {
return isDescendants;
}
// TODO Fix whether this is an descendant XMLName at construction?
/** @deprecated */
@Deprecated
void setIsDescendants() {
// if (isDescendants) throw new IllegalStateException();
isDescendants = true;
}
}