1 package net.sf.saxon.style; 2 import net.sf.saxon.expr.*; 3 import net.sf.saxon.instruct.Executable; 4 import net.sf.saxon.instruct.ForEachGroup; 5 import net.sf.saxon.om.AttributeCollection; 6 import net.sf.saxon.om.Axis; 7 import net.sf.saxon.pattern.Pattern; 8 import net.sf.saxon.pattern.PatternSponsor; 9 import net.sf.saxon.trans.XPathException; 10 import net.sf.saxon.value.EmptySequence; 11 import net.sf.saxon.value.SequenceType; 12 13 import java.util.Comparator ; 14 15 19 20 public final class XSLForEachGroup extends StyleElement { 21 22 private Expression select = null; 23 private Expression groupBy = null; 24 private Expression groupAdjacent = null; 25 private Pattern starting = null; 26 private Pattern ending = null; 27 private String collationName; 28 29 33 34 public boolean isInstruction() { 35 return true; 36 } 37 38 41 42 protected boolean isPermittedChild(StyleElement child) { 43 return (child instanceof XSLSort); 44 } 45 46 50 51 public boolean mayContainSequenceConstructor() { 52 return true; 53 } 54 55 public void prepareAttributes() throws XPathException { 56 57 AttributeCollection atts = getAttributeList(); 58 59 String selectAtt = null; 60 String groupByAtt = null; 61 String groupAdjacentAtt = null; 62 String startingAtt = null; 63 String endingAtt = null; 64 65 for (int a=0; a<atts.getLength(); a++) { 66 int nc = atts.getNameCode(a); 67 String f = getNamePool().getClarkName(nc); 68 if (f==StandardNames.SELECT) { 69 selectAtt = atts.getValue(a); 70 } else if (f==StandardNames.GROUP_BY) { 71 groupByAtt = atts.getValue(a); 72 } else if (f==StandardNames.GROUP_ADJACENT) { 73 groupAdjacentAtt = atts.getValue(a); 74 } else if (f==StandardNames.GROUP_STARTING_WITH) { 75 startingAtt = atts.getValue(a); 76 } else if (f==StandardNames.GROUP_ENDING_WITH) { 77 endingAtt = atts.getValue(a); 78 } else if (f==StandardNames.COLLATION) { 79 collationName = atts.getValue(a).trim(); 80 } else { 81 checkUnknownAttribute(nc); 82 } 83 } 84 85 if (selectAtt==null) { 86 reportAbsence("select"); 87 select = EmptySequence.getInstance(); } else { 89 select = makeExpression(selectAtt); 90 } 91 92 int c = (groupByAtt==null ? 0 : 1) + 93 (groupAdjacentAtt==null ? 0 : 1) + 94 (startingAtt==null ? 0 : 1) + 95 (endingAtt==null ? 0 : 1);; 96 if (c!=1) { 97 compileError("Exactly one of the attributes group-by, group-adjacent, group-starting-with, " + 98 "and group-ending-with must be specified", "XTSE1080"); 99 } 100 101 if (groupByAtt != null) { 102 groupBy = makeExpression(groupByAtt); 103 } 104 105 if (groupAdjacentAtt != null) { 106 groupAdjacent = makeExpression(groupAdjacentAtt); 107 } 108 109 if (startingAtt != null) { 110 starting = makePattern(startingAtt); 111 } 112 113 if (endingAtt != null) { 114 ending = makePattern(endingAtt); 115 } 116 117 if (collationName!=null && groupBy==null && groupAdjacent==null) { 118 compileError("A collation may be specified only if group-by or group-adjacent is specified", "XTSE1090"); 119 } 120 } 121 122 public void validate() throws XPathException { 123 checkWithinTemplate(); 124 checkSortComesFirst(false); 125 select = typeCheck("select", select); 126 127 ExpressionLocation locator = new ExpressionLocation(this); 128 if (groupBy != null) { 129 groupBy = typeCheck("group-by", groupBy); 130 try { 131 RoleLocator role = 132 new RoleLocator(RoleLocator.INSTRUCTION, "xsl:for-each-group/group-by", 0, null); 133 role.setSourceLocator(locator); 134 groupBy = TypeChecker.staticTypeCheck(groupBy, 135 SequenceType.ATOMIC_SEQUENCE, 136 false, role, getStaticContext()); 137 } catch (XPathException err) { 138 compileError(err); 139 } 140 } else if (groupAdjacent != null) { 141 groupAdjacent = typeCheck("group-adjacent", groupAdjacent); 142 try { 143 RoleLocator role = 144 new RoleLocator(RoleLocator.INSTRUCTION, "xsl:for-each-group/group-adjacent", 0, null); 145 role.setSourceLocator(locator); 146 role.setErrorCode("XTTE1100"); 147 groupAdjacent = TypeChecker.staticTypeCheck(groupAdjacent, 148 SequenceType.SINGLE_ATOMIC, 149 false, role, getStaticContext()); 150 } catch (XPathException err) { 151 compileError(err); 152 } 153 } 154 155 starting = typeCheck("starting", starting); 156 ending = typeCheck("ending", ending); 157 158 if (starting != null || ending != null) { 159 try { 160 RoleLocator role = 161 new RoleLocator(RoleLocator.INSTRUCTION, "xsl:for-each-group/select", 0, null); 162 role.setSourceLocator(locator); 163 role.setErrorCode("XTTE1120"); 164 select = TypeChecker.staticTypeCheck(select, 165 SequenceType.NODE_SEQUENCE, 166 false, role, getStaticContext()); 167 } catch (XPathException err) { 168 String prefix = (starting != null ? 169 "With group-starting-with attribute: " : 170 "With group-ending-with attribute: "); 171 compileError(prefix + err.getMessage(), err.getErrorCodeLocalPart()); 172 } 173 } 174 } 175 176 public Expression compile(Executable exec) throws XPathException { 177 178 Comparator collator = null; 179 if (collationName != null) { 180 collator = getPrincipalStylesheet().findCollation(collationName); 181 if (collator==null) { 182 compileError("The collation name '" + collationName + "' has not been defined", "XTDE1110"); 183 } 184 } 185 186 byte algorithm = 0; 187 Expression key = null; 188 if (groupBy != null) { 189 algorithm = ForEachGroup.GROUP_BY; 190 key = groupBy; 191 } else if (groupAdjacent != null) { 192 algorithm = ForEachGroup.GROUP_ADJACENT; 193 key = groupAdjacent; 194 } else if (starting != null) { 195 algorithm = ForEachGroup.GROUP_STARTING; 196 key = new PatternSponsor(starting); 197 } else if (ending != null) { 198 algorithm = ForEachGroup.GROUP_ENDING; 199 key = new PatternSponsor(ending); 200 } 201 202 Expression action = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true); 205 if (action == null) { 206 return EmptySequence.getInstance(); 208 } 209 try { 210 ForEachGroup inst = new ForEachGroup( 211 select, 212 action.simplify(getStaticContext()), 213 algorithm, 214 key, 215 collator, 216 makeSortKeys() ); 217 ExpressionTool.makeParentReferences(inst); 218 return inst; 219 } catch (XPathException e) { 220 compileError(e); 221 return null; 222 } 223 224 } 225 226 } 227 228 | Popular Tags |