}
@Override
public void visitGetStm(GetStm s) {
printProgress(s);
final XMLGraph g = b.getOut(s, s.getDest());
boolean empty;
if (g.isUnknown()) {
empty = false;
} else {
empty = true;
for (int i : g.getRoots()) {
// TODO use Emptiness instead, or upgrade sharpen() so we can just test
// if roots are empty
// true=definitely empty, false=maybe empty
empty &= g.getNode(i).process(new CachedNodeProcessor<Boolean>() {
@Override
public Boolean cycle() {
return false;
}
@Override
public Boolean process(AttributeNode n) {
return false;
}
@Override
public Boolean process(ElementNode n) {
return false;
}
@Override
public Boolean process(TextNode n) {
if (n.getText().isEmpty())
return true;
else
return false;
}
@Override
public Boolean process(OneOrMoreNode n) {
return g.getNode(n.getContent()).process(this);
}
@Override
public Boolean process(ChoiceNode n) {
if (n.isGap() && n.isOpen())
return false; // gaps are not to be considered "empty content"
else
return null;
}
@Override
public Boolean process(MultiContentNode n) {
boolean empty = true;
for (int child : n.getContents()) {
empty &= g.getNode(child).process(this);
}
return empty;
}
});
}
}
if (empty)
error(s, ErrorType.EMPTY_RESULT, "'%s' has empty result", s.getOpName());
}
@Override
public void visitInsertStm(InsertStm s) {
printProgress(s);
checkNonEmpty(s);
}
@Override
public void visitNodeStm(NodeStm s) {
printProgress(s);
// TODO: check NodeStm
}
@Override
public void visitPlugStm(final PlugStm s) {
printProgress(s);
XMLGraph g = b.getIn(s, s.getBase());
if (g.isUnknown())
return;
switch (s.getKind()) {
case PLUG:
case PLUGMULTI:
case PLUGWRAP: {
if (!g.getOpenAttributeGaps().contains(s.getGapName())
&& !g.getOpenTemplateGaps().contains(s.getGapName()))
error(s, ErrorType.MISSING_GAP, "the gap '%s' is absent", s.getGapName());
if (g.getOpenAttributeGaps().contains(s.getGapName())
&& !b.getIn(s, s.getXMLSource()).getRoots().isEmpty())
error(s, ErrorType.XML_IN_ATTRIBUTE, "maybe plugging XML data into attribute gap '%s'", s.getGapName());
final String gapType = g.getGapTypeMap().get(s.getGapName());
if (gapType != null) {
XMLGraph value_xg = b.getIn(s, s.getXMLSource());
XMLGraph type_xg = b.getGlobalXMLGraph().clone();
// SequenceNode n = b.getSchemaTypes().get(gapType);
Node n = fg.getTypemap().get(gapType);
type_xg.useFragment(new XMLGraphFragment(n, null, null, null));
Validator validator = new Validator(new ValidationErrorHandler() {
public boolean error(ElementNode n, Origin origin, String msg,
String example, Origin schema) {
if (example == null)
example = "";
XMLGraphChecker.this.error(
s,
ErrorType.INVALID_PLUG_TYPE,
"Plug statement violates the gap type %s\n" +
"because of %s created at %s\n" +
"%s %s",
gapType,
formatNode(n),
origin,
msg,
formatExample(example));
return true;
}
});
validator.validate(value_xg, type_xg, -1);
}
break;
}
case CLOSE:
if (g.getGapTypeMap().isEmpty())
return;
XMLGraph empty_xg = b.getGlobalXMLGraph().clone();
empty_xg.useFragment(new XMLGraphFragment(b.getEmptySequence(), null, null, null));
XMLGraph type_xg = b.getGlobalXMLGraph().clone();
for (final Map.Entry<String,String> gapentry : g.getGapTypeMap().entrySet()) {
final String gapName = gapentry.getKey();
final String gapType = gapentry.getValue();
Node n = fg.getTypemap().get(gapType);
type_xg.useFragment(new XMLGraphFragment(n, null, null, null));
Validator validator = new Validator(new ValidationErrorHandler() {
public boolean error(ElementNode n, Origin origin, String msg,
String example, Origin schema) {
if (example == null)
example = "";
XMLGraphChecker.this.error(
s,
ErrorType.INVALID_PLUG_TYPE,
"Close statement violates the type of gap %s\n" +
"%s does not permit an empty sequence\n" +
"Perhaps add '?' or '*' quantifier?",
gapName,
gapType);
return true;
}
});
validator.validate(empty_xg, type_xg, -1);
}
break;
}
}
@Override
public void visitRemoveStm(RemoveStm s) {
printProgress(s);
checkNonEmpty(s);
}
@Override
public void visitSetStm(SetStm s) {
printProgress(s);
checkNonEmpty(s);
}
});
}
for (Statement s : fg.getNodes()) {
s.visitBy(new BasicStatementVisitor() {
@Override
public void visitAnalyzeStm(final AnalyzeStm s) {
if (s.getKind() == AnalyzeStm.Kind.HOTSPOT)
return; // hotspots should not be analyzed here
printProgress(s);
XMLGraph value_xg = b.getIn(s, s.getBase());
if (value_xg.isUnknown()) {
String message;
if (s.getKind() == AnalyzeStm.Kind.TYPEANNOTATION) {
message = "Non-validated XML data assigned to type-annotated variable";
} else {
message = "Non-validated XML data at 'analyze' statement";
}
error(s, ErrorType.INVALID, message);
} else {
Validator validator = new Validator(new ValidationErrorHandler() {
public boolean error(ElementNode n, Origin origin, String msg,
String example, Origin schema) {
XMLGraphChecker.this.error(
s.getOrigin(),
ErrorType.INVALID,
"Problem in %s created at %s\n" +
"%s %s",
formatNode(n),
origin,
msg,
formatExample(example));
return true;
}
});
XMLGraph type_xg = b.getGlobalXMLGraph().clone();
SchemaType schema = s.getSchema();
String type = schema.getType();
Node n = fg.getTypemap().get(type);
if (n == null)
throw new XMLAnalysisException("No schema definition found for " + type, s.getOrigin());
type_xg.useFragment(new XMLGraphFragment(n, null, null, null));
Map<String,String> gaptypes = schema.getGapTypes();
if (gaptypes == null)
gaptypes = Collections.emptyMap();
for (Map.Entry<String,String> valueGapType : value_xg.getGapTypeMap().entrySet()) {
String typeGapType = gaptypes.get(valueGapType.getKey());