net.sf.saxon.style.XSLCharacterMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Saxon-HE Show documentation
Show all versions of Saxon-HE Show documentation
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 Saxonica Limited.
// 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/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.style;
import net.sf.saxon.z.IntHashMap;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.Err;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.value.Whitespace;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* An xsl:character-map declaration in the stylesheet.
*/
public class XSLCharacterMap extends StyleElement {
/*@Nullable*/ String use;
// the value of the use-character-maps attribute, as supplied
List characterMapElements = null;
// list of XSLCharacterMap objects referenced by this one
boolean validated = false;
// set to true once validate() has been called
boolean redundant = false;
// set to true if another character-map overrrides this one
/**
* Ask whether this node is a declaration, that is, a permitted child of xsl:stylesheet
* (including xsl:include and xsl:import).
*
* @return true for this element
*/
@Override
public boolean isDeclaration() {
return true;
}
/**
* Get the fingerprint of the name of this character map
*
* @return the fingerprint value
*/
public StructuredQName getCharacterMapName() {
StructuredQName name = getObjectName();
if (name == null) {
try {
return makeQName(getAttributeValue("", "name"));
} catch (Exception err) {
// the error will be reported later
return new StructuredQName("", "", "unnamedCharacterMap_" + hashCode());
}
}
return name;
}
/**
* Test whether this character map is redundant (because another with the
* same name has higher import precedence). Note that a character map is not
* considered redundant simply because it is not referenced in an xsl:output
* declaration; we allow character-maps to be selected at run-time using the
* setOutputProperty() API.
*
* @return true if this character map is redundant
*/
public boolean isRedundant() {
return redundant;
}
/**
* Validate the attributes on this instruction
*
* @throws XPathException
*/
public void prepareAttributes() throws XPathException {
String name = null;
use = null;
AttributeCollection atts = getAttributeList();
for (int a = 0; a < atts.getLength(); a++) {
String f = atts.getQName(a);
if (f.equals("name")) {
name = Whitespace.trim(atts.getValue(a));
} else if (f.equals("use-character-maps")) {
use = atts.getValue(a);
} else {
checkUnknownAttribute(atts.getNodeName(a));
}
}
if (name == null) {
reportAbsence("name");
name = "unnamedCharacterMap_" + hashCode();
}
try {
setObjectName(makeQName(name));
} catch (NamespaceException err) {
compileError(err.getMessage(), "XTSE0280");
name = "unnamedCharacterMap_" + hashCode();
setObjectName(new StructuredQName("", "", name));
} catch (XPathException err) {
compileError(err.getMessage(), "XTSE0020");
name = "unnamedCharacterMap_" + hashCode();
setObjectName(new StructuredQName("", "", name));
}
}
public void validate(ComponentDeclaration decl) throws XPathException {
if (validated) return;
// check that this is a top-level declaration
checkTopLevel("XTSE0010", false);
// check that the only children are xsl:output-character elements
AxisIterator kids = iterateAxis(AxisInfo.CHILD);
while (true) {
Item child = kids.next();
if (child == null) {
break;
}
if (!(child instanceof XSLOutputCharacter)) {
compileError("Only xsl:output-character is allowed within xsl:character-map", "XTSE0010");
}
}
// check that there isn't another character-map with the same name and import
// precedence
PrincipalStylesheetModule psm = getPrincipalStylesheetModule();
ComponentDeclaration other = psm.getCharacterMap(getObjectName());
if (other.getSourceElement() != this) {
if (decl.getPrecedence() == other.getPrecedence()) {
compileError("There are two character-maps with the same name and import precedence", "XTSE1580");
} else if (decl.getPrecedence() < other.getPrecedence()) {
redundant = true;
}
}
// validate the use-character-maps attribute
if (use != null) {
// identify any character maps that this one refers to
characterMapElements = new ArrayList(5);
StringTokenizer st = new StringTokenizer(use, " \t\n\r", false);
while (st.hasMoreTokens()) {
String displayname = st.nextToken();
try {
String[] parts = NameChecker.getQNameParts(displayname);
String uri = getURIForPrefix(parts[0], false);
if (uri == null) {
compileError("Undeclared namespace prefix " + Err.wrap(parts[0])
+ " in character map name", "XTSE0280");
}
StructuredQName qn = new StructuredQName(parts[0], uri, parts[1]);
ComponentDeclaration charMapDecl = psm.getCharacterMap(qn);
if (charMapDecl == null) {
compileError("No character-map named '" + displayname + "' has been defined", "XTSE1590");
} else {
XSLCharacterMap ref = (XSLCharacterMap) charMapDecl.getSourceElement();
characterMapElements.add(ref);
}
} catch (QNameException err) {
compileError("Invalid character-map name. " + err.getMessage(), "XTSE1590");
}
}
// check for circularity
for (Object characterMapElement : characterMapElements) {
((XSLCharacterMap) characterMapElement).checkCircularity(this);
}
}
validated = true;
}
/**
* Check for circularity: specifically, check that this attribute set does not contain
* a direct or indirect reference to the one supplied as a parameter
*
* @param origin the start point of the search
* @throws net.sf.saxon.trans.XPathException
* if an error is detected
*/
private void checkCircularity(XSLCharacterMap origin) throws XPathException {
if (this == origin) {
compileError("The definition of the character map is circular", "XTSE1600");
characterMapElements = null; // for error recovery
} else {
if (!validated) {
// if this attribute set isn't validated yet, we don't check it.
// The circularity will be detected when the last attribute set in the cycle
// gets validated
return;
}
if (characterMapElements != null) {
for (Object characterMapElement : characterMapElements) {
((XSLCharacterMap) characterMapElement).checkCircularity(origin);
}
}
}
}
/**
* Assemble all the mappings defined by this character map, adding them to a
* HashMap that maps integer codepoints to strings
*
* @param map an IntHash map populated with the character mappings
*/
public void assemble(IntHashMap map) {
if (characterMapElements != null) {
for (XSLCharacterMap charmap : characterMapElements) {
charmap.assemble(map);
}
}
AxisIterator kids = iterateAxis(AxisInfo.CHILD);
while (true) {
Item child = kids.next();
if (child == null) {
return;
}
XSLOutputCharacter oc = (XSLOutputCharacter) child;
map.put(oc.getCodePoint(), oc.getReplacementString());
}
}
public void compileDeclaration(Compilation compilation, ComponentDeclaration decl) throws XPathException {
// no action
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy