use of org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat in project tracecompass by tracecompass.
the class CustomEvent method processData.
// ------------------------------------------------------------------------
// Other operations
// ------------------------------------------------------------------------
private void processData() {
// Remove the values as they are processed, so we can process the extra values at the end
String timestampString = fData.remove(Tag.TIMESTAMP);
String timestampInputFormat = fData.remove(Key.TIMESTAMP_INPUT_FORMAT);
ITmfTimestamp timestamp = null;
if (timestampInputFormat != null && timestampString != null) {
TmfTimestampFormat timestampFormat = new TmfTimestampFormat(timestampInputFormat);
try {
long time = timestampFormat.parseValue(timestampString);
timestamp = TmfTimestamp.fromNanos(getTrace().getTimestampTransform().transform(time));
setTimestamp(timestamp);
} catch (ParseException e) {
setTimestamp(TmfTimestamp.ZERO);
}
} else {
setTimestamp(TmfTimestamp.ZERO);
}
// Update the custom event type of this event if set
String eventName = fData.remove(Tag.EVENT_TYPE);
ITmfEventType type = getType();
if (eventName != null && type instanceof CustomEventType) {
((CustomEventType) type).setName(eventName);
}
Map<String, TmfEventField> fieldMap = new LinkedHashMap<>();
for (OutputColumn outputColumn : fDefinition.outputs) {
if (outputColumn.tag.equals(Tag.TIMESTAMP)) {
if (timestamp != null && fDefinition.timeStampOutputFormat != null && !fDefinition.timeStampOutputFormat.isEmpty()) {
TmfTimestampFormat timestampFormat = new TmfTimestampFormat(fDefinition.timeStampOutputFormat);
fieldMap.put(outputColumn.name, new TmfEventField(outputColumn.name, timestampFormat.format(timestamp.getValue()), null));
}
} else if (outputColumn.tag.equals(Tag.OTHER) || outputColumn.tag.equals(Tag.MESSAGE)) {
Object key = (outputColumn.tag.equals(Tag.OTHER) ? outputColumn.name : outputColumn.tag);
fieldMap.put(outputColumn.name, new TmfEventField(outputColumn.name, nullToEmptyString(fData.remove(key)), null));
}
}
// This event contains extra values, we process them now
for (Entry<Object, String> entry : fData.entrySet()) {
String fieldName = nullToEmptyString(entry.getKey().toString());
// Ignore extra fields if a field of same name is already set
if (!fieldMap.containsKey(fieldName)) {
fieldMap.put(fieldName, new CustomExtraField(fieldName, nullToEmptyString(entry.getValue()), null));
}
}
setContent(new CustomEventContent(customEventContent.getName(), customEventContent.getValue(), fieldMap.values().toArray(new ITmfEventField[fieldMap.size()])));
fData = null;
}
use of org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat in project tracecompass by tracecompass.
the class CustomTxtParserInputWizardPage method validateLine.
/**
* Validate an input line.
*
* @param inputLine
* The line to clean up
* @param name
* The name of the line
* @return The cleaned up line
*/
public StringBuilder validateLine(InputLine inputLine, String name) {
StringBuilder errors = new StringBuilder();
Line line = null;
if (selectedLine != null && selectedLine.inputLine.equals(inputLine)) {
line = selectedLine;
}
try {
Pattern.compile(inputLine.getRegex());
if (line != null) {
line.regexText.setBackground(fBGColor);
}
} catch (PatternSyntaxException e) {
// $NON-NLS-1$ //$NON-NLS-2$
errors.append("Enter a valid regular expression (Line " + name + "). ");
if (line != null) {
line.regexText.setBackground(COLOR_LIGHT_RED);
}
}
if (inputLine.getMinCount() == -1) {
// $NON-NLS-1$ //$NON-NLS-2$
errors.append("Enter a minimum value for cardinality (Line " + name + "). ");
if (line != null) {
line.cardinalityMinText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (line != null) {
line.cardinalityMinText.setBackground(fBGColor);
}
}
if (inputLine.getMaxCount() == -1) {
// $NON-NLS-1$ //$NON-NLS-2$
errors.append("Enter a maximum value for cardinality (Line " + name + "). ");
if (line != null) {
line.cardinalityMaxText.setBackground(COLOR_LIGHT_RED);
}
} else if (inputLine.getMinCount() > inputLine.getMaxCount()) {
// $NON-NLS-1$ //$NON-NLS-2$
errors.append("Enter correct (min <= max) values for cardinality (Line " + name + "). ");
if (line != null) {
line.cardinalityMinText.setBackground(COLOR_LIGHT_RED);
}
if (line != null) {
line.cardinalityMaxText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (line != null) {
line.cardinalityMaxText.setBackground(fBGColor);
}
}
if (inputLine.eventType != null && inputLine.eventType.trim().isEmpty()) {
// $NON-NLS-1$ //$NON-NLS-2$
errors.append("Enter the event type (Line " + name + "). ");
if (line != null) {
line.eventTypeText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (line != null) {
line.eventTypeText.setBackground(fBGColor);
}
}
for (int i = 0; inputLine.columns != null && i < inputLine.columns.size(); i++) {
InputData inputData = inputLine.columns.get(i);
InputGroup group = null;
if (line != null) {
group = line.inputs.get(i);
}
if (inputData.tag.equals(Tag.TIMESTAMP)) {
timestampFound = true;
if (inputData.format.length() == 0) {
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
errors.append("Enter the input format for the Time Stamp (Line " + name + " Group " + (i + 1) + "). ");
if (group != null) {
group.tagText.setBackground(COLOR_LIGHT_RED);
}
} else {
try {
new TmfTimestampFormat(inputData.format);
if (group != null) {
group.tagText.setBackground(fBGColor);
}
} catch (IllegalArgumentException e) {
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
errors.append("Enter a valid input format for the Time Stamp (Line " + name + " Group " + (i + 1) + ") [" + e.getMessage() + "]. ");
if (group != null) {
group.tagText.setBackground(COLOR_LIGHT_RED);
}
}
}
} else if (inputData.tag.equals(Tag.OTHER)) {
if (inputData.name.isEmpty()) {
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
errors.append("Enter a name for the data group (Line " + name + " Group " + (i + 1) + "). ");
if (group != null) {
group.tagText.setBackground(COLOR_LIGHT_RED);
}
} else if (Tag.fromLabel(inputData.name) != null) {
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
errors.append("Cannot use reserved name for the data group (Line " + name + " Group " + (i + 1) + "). ");
if (group != null) {
group.tagText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (group != null) {
group.tagText.setBackground(fBGColor);
}
}
} else {
if (group != null) {
group.tagText.setBackground(fBGColor);
}
}
}
for (int i = 0; inputLine.childrenInputs != null && i < inputLine.childrenInputs.size(); i++) {
// $NON-NLS-1$
errors.append(validateLine(inputLine.childrenInputs.get(i), name + "." + (i + 1)));
}
return errors;
}
use of org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat in project tracecompass by tracecompass.
the class CustomTxtParserInputWizardPage method updatePreviews.
private void updatePreviews(boolean updateAll) {
if (inputText == null) {
// early update during construction
return;
}
inputText.setBackground(fBGColor);
inputText.setStyleRanges(new StyleRange[] {});
try (Scanner scanner = new Scanner(inputText.getText())) {
// $NON-NLS-1$
scanner.useDelimiter("\n");
int rawPos = 0;
// skip starting delimiters
// $NON-NLS-1$
String skip = scanner.findWithinHorizon("\\A\n+", 0);
if (skip != null) {
rawPos += skip.length();
}
timeStampFormat = null;
if (selectedLine != null) {
for (InputGroup input : selectedLine.inputs) {
input.previewText.setText(Messages.CustomTxtParserInputWizardPage_noMathcingLine);
}
}
Map<Object, String> data = new HashMap<>();
int rootLineMatches = 0;
String firstEntryTimeStamp = null;
String firstEntryTimeStampInputFormat = null;
String line = null;
// needed because of JDT bug with continue at label
boolean lineIsNull = true;
event: while (scanner.hasNext() || !lineIsNull) {
if (rootLineMatches > 0 && !updateAll) {
break;
}
if (line == null) {
line = scanner.next();
lineIsNull = false;
}
int length = line.length();
// $NON-NLS-1$ //$NON-NLS-2$
String log = line.replace("\r", "");
for (InputLine rootInputLine : definition.inputs) {
Pattern pattern;
try {
pattern = rootInputLine.getPattern();
} catch (PatternSyntaxException e) {
continue;
}
Matcher matcher = pattern.matcher(log);
if (matcher.matches()) {
rootLineMatches++;
inputText.setStyleRange(new StyleRange(rawPos, length, COLOR_BLACK, COLOR_YELLOW, SWT.ITALIC));
data = new HashMap<>();
timeStampFormat = null;
updatePreviewLine(rootInputLine, matcher, data, rawPos, rootLineMatches);
if (rootLineMatches == 1) {
firstEntryTimeStamp = data.get(Tag.TIMESTAMP);
firstEntryTimeStampInputFormat = timeStampFormat.toString();
}
HashMap<InputLine, Integer> countMap = new HashMap<>();
InputLine currentInput = null;
if (rootInputLine.childrenInputs != null && !rootInputLine.childrenInputs.isEmpty()) {
currentInput = rootInputLine.childrenInputs.get(0);
countMap.put(currentInput, 0);
}
// +1 for \n
rawPos += length + 1;
while (scanner.hasNext()) {
line = scanner.next();
length = line.length();
// $NON-NLS-1$ //$NON-NLS-2$
log = line.replace("\r", "");
boolean processed = false;
if (currentInput == null) {
for (InputLine input : definition.inputs) {
try {
matcher = input.getPattern().matcher(log);
} catch (PatternSyntaxException e) {
continue;
}
if (matcher.matches()) {
continue event;
}
}
} else {
if (checkNotNull(countMap.get(currentInput)) >= currentInput.getMinCount()) {
List<InputLine> nextInputs = currentInput.getNextInputs(countMap);
if (nextInputs.isEmpty() || nextInputs.get(nextInputs.size() - 1).getMinCount() == 0) {
for (InputLine input : definition.inputs) {
try {
matcher = input.getPattern().matcher(log);
} catch (PatternSyntaxException e) {
continue;
}
if (matcher.matches()) {
continue event;
}
}
}
for (InputLine input : nextInputs) {
try {
matcher = input.getPattern().matcher(log);
} catch (PatternSyntaxException e) {
continue;
}
if (matcher.matches()) {
inputText.setStyleRange(new StyleRange(rawPos, length, COLOR_BLACK, COLOR_LIGHT_YELLOW, SWT.ITALIC));
currentInput = input;
updatePreviewLine(currentInput, matcher, data, rawPos, rootLineMatches);
if (countMap.get(currentInput) == null) {
countMap.put(currentInput, 1);
} else {
countMap.put(currentInput, checkNotNull(countMap.get(currentInput)) + 1);
}
Iterator<InputLine> iter = countMap.keySet().iterator();
while (iter.hasNext()) {
InputLine inputLine = iter.next();
if (inputLine.level > currentInput.level) {
iter.remove();
}
}
if (currentInput.childrenInputs != null && !currentInput.childrenInputs.isEmpty()) {
currentInput = currentInput.childrenInputs.get(0);
countMap.put(currentInput, 0);
} else {
if (checkNotNull(countMap.get(currentInput)) >= currentInput.getMaxCount()) {
if (!currentInput.getNextInputs(countMap).isEmpty()) {
currentInput = currentInput.getNextInputs(countMap).get(0);
countMap.putIfAbsent(currentInput, 0);
iter = countMap.keySet().iterator();
while (iter.hasNext()) {
InputLine inputLine = iter.next();
if (inputLine.level > currentInput.level) {
iter.remove();
}
}
} else {
currentInput = null;
}
}
}
processed = true;
break;
}
}
}
if (!processed && currentInput != null) {
matcher = null;
try {
matcher = currentInput.getPattern().matcher(log);
} catch (PatternSyntaxException e) {
}
if (matcher != null && matcher.matches()) {
inputText.setStyleRange(new StyleRange(rawPos, length, COLOR_BLACK, COLOR_LIGHT_YELLOW, SWT.ITALIC));
updatePreviewLine(currentInput, matcher, data, rawPos, rootLineMatches);
countMap.put(currentInput, checkNotNull(countMap.get(currentInput)) + 1);
if (currentInput.childrenInputs != null && !currentInput.childrenInputs.isEmpty()) {
currentInput = currentInput.childrenInputs.get(0);
countMap.put(currentInput, 0);
} else {
if (checkNotNull(countMap.get(currentInput)) >= currentInput.getMaxCount()) {
if (!currentInput.getNextInputs(countMap).isEmpty()) {
currentInput = currentInput.getNextInputs(countMap).get(0);
if (countMap.get(currentInput) == null) {
countMap.put(currentInput, 0);
}
Iterator<InputLine> iter = countMap.keySet().iterator();
while (iter.hasNext()) {
InputLine inputLine = iter.next();
if (inputLine.level > currentInput.level) {
iter.remove();
}
}
} else {
currentInput = null;
}
}
}
}
}
}
// +1 for \n
rawPos += length + 1;
}
break;
}
}
// +1 for \n
rawPos += length + 1;
line = null;
lineIsNull = true;
}
if (rootLineMatches == 1) {
firstEntryTimeStamp = data.get(Tag.TIMESTAMP);
firstEntryTimeStampInputFormat = timeStampFormat.toString();
}
if (firstEntryTimeStamp == null) {
timestampPreviewText.setText(Messages.CustomTxtParserInputWizardPage_noTimestampGroup);
if (selectedLine != null) {
for (InputGroup group : selectedLine.inputs) {
if (group.tagCombo.getText().equals(Tag.TIMESTAMP.toString())) {
timestampPreviewText.setText(Messages.CustomTxtParserInputWizardPage_noMatchingTimestamp);
break;
}
}
}
} else {
try {
TmfTimestampFormat timestampFormat = new TmfTimestampFormat(firstEntryTimeStampInputFormat);
long timestamp = timestampFormat.parseValue(firstEntryTimeStamp);
if (timestampOutputFormatText.getText().trim().isEmpty()) {
timestampFormat = new TmfTimestampFormat();
} else {
timestampFormat = new TmfTimestampFormat(timestampOutputFormatText.getText().trim());
}
timestampPreviewText.setText(timestampFormat.format(timestamp));
} catch (ParseException e) {
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
timestampPreviewText.setText("*parse exception* [" + firstEntryTimeStamp + "] <> [" + firstEntryTimeStampInputFormat + "]");
} catch (IllegalArgumentException e) {
// $NON-NLS-1$ //$NON-NLS-2$
timestampPreviewText.setText("*parse exception* [Illegal Argument: " + e.getMessage() + "]");
}
}
}
}
use of org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat in project tracecompass by tracecompass.
the class CustomXmlParserInputWizardPage method updatePreviews.
private void updatePreviews() {
if (inputText == null) {
// early update during construction
return;
}
inputText.setBackground(fBGColor);
inputText.setStyleRanges(new StyleRange[] {});
if (selectedElement == null) {
return;
}
initValues();
selectedElement.updatePreview();
if (timestampValue != null && timestampFormat != null) {
try {
TmfTimestampFormat format = new TmfTimestampFormat(timestampFormat.toString());
long timestamp = format.parseValue(timestampValue.toString());
if (timestampOutputFormatText.getText().trim().isEmpty()) {
format = new TmfTimestampFormat();
} else {
format = new TmfTimestampFormat(timestampOutputFormatText.getText().trim());
}
timestampPreviewText.setText(format.format(timestamp));
} catch (ParseException e) {
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
timestampPreviewText.setText("*parse exception* [" + timestampValue + "] <> [" + timestampFormat + "]");
} catch (IllegalArgumentException e) {
// $NON-NLS-1$
timestampPreviewText.setText("*parse exception* [Illegal Argument]");
}
} else {
// $NON-NLS-1$
timestampPreviewText.setText("*no matching time stamp*");
}
}
use of org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat in project tracecompass by tracecompass.
the class CustomXmlParserInputWizardPage method validateElement.
/**
* Clean up the specified XML element.
*
* @param inputElement
* The element to clean up
* @return The validated element
*/
public List<String> validateElement(CustomXmlInputElement inputElement) {
List<String> errors = new ArrayList<>();
ElementNode elementNode = null;
if (selectedElement != null && selectedElement.inputElement.equals(inputElement)) {
elementNode = selectedElement;
}
if (inputElement == definition.rootInputElement) {
if (inputElement.getElementName().length() == 0) {
errors.add(Messages.CustomXmlParserInputWizardPage_missingDocumentElementError);
if (elementNode != null) {
elementNode.elementNameText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (elementNode != null) {
elementNode.elementNameText.setBackground(fBGColor);
}
}
}
if (inputElement != definition.rootInputElement) {
if (inputElement.isLogEntry()) {
logEntryFound = true;
}
if (inputElement.getInputTag().equals(Tag.TIMESTAMP)) {
timestampFound = true;
if (inputElement.getInputFormat().length() == 0) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementMissingTimestampFmtError, getName(inputElement)));
if (elementNode != null) {
elementNode.tagText.setBackground(COLOR_LIGHT_RED);
}
} else {
try {
new TmfTimestampFormat(inputElement.getInputFormat());
if (elementNode != null) {
elementNode.tagText.setBackground(fBGColor);
}
} catch (IllegalArgumentException e) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementInvalidTimestampFmtError, getName(inputElement)));
if (elementNode != null) {
elementNode.tagText.setBackground(COLOR_LIGHT_RED);
}
}
}
} else if (inputElement.getInputName().length() == 0) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementMissingInputNameError, getName(inputElement)));
if (elementNode != null) {
elementNode.tagText.setBackground(COLOR_LIGHT_RED);
}
} else if (inputElement.getInputTag().equals(Tag.OTHER) && Tag.fromLabel(inputElement.getInputName()) != null) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementReservedInputNameError, getName(inputElement)));
if (elementNode != null) {
elementNode.tagText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (elementNode != null) {
elementNode.tagText.setBackground(fBGColor);
}
}
if (inputElement.getEventType() != null && inputElement.getEventType().trim().isEmpty()) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_emptyEventTypeError, getName(inputElement)));
if (elementNode != null) {
elementNode.eventTypeText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (elementNode != null) {
elementNode.eventTypeText.setBackground(fBGColor);
}
}
}
if (inputElement.getAttributes() != null) {
if (elementNode != null) {
for (Attribute attribute : elementNode.attributes) {
attribute.attributeNameText.setBackground(fBGColor);
}
}
for (int i = 0; i < inputElement.getAttributes().size(); i++) {
CustomXmlInputAttribute attribute = inputElement.getAttributes().get(i);
boolean duplicate = false;
for (int j = i + 1; j < inputElement.getAttributes().size(); j++) {
CustomXmlInputAttribute otherAttribute = inputElement.getAttributes().get(j);
if (otherAttribute.getAttributeName().equals(attribute.getAttributeName())) {
duplicate = true;
if (elementNode != null) {
elementNode.attributes.get(j).attributeNameText.setBackground(COLOR_LIGHT_RED);
}
}
}
if (attribute.getAttributeName().length() == 0) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeMissingNameError, getName(inputElement)));
if (elementNode != null) {
elementNode.attributes.get(i).attributeNameText.setBackground(COLOR_LIGHT_RED);
}
} else if (duplicate) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeDuplicateNameError, getName(attribute, inputElement)));
if (elementNode != null) {
elementNode.attributes.get(i).attributeNameText.setBackground(COLOR_LIGHT_RED);
}
}
if (attribute.getInputTag().equals(Tag.TIMESTAMP)) {
timestampFound = true;
if (attribute.getInputFormat().length() == 0) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeMissingTimestampFmtError, getName(attribute, inputElement)));
if (elementNode != null) {
elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED);
}
} else {
try {
new TmfTimestampFormat(attribute.getInputFormat());
if (elementNode != null) {
elementNode.attributes.get(i).tagText.setBackground(fBGColor);
}
} catch (IllegalArgumentException e) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeInvalidTimestampFmtError, getName(attribute, inputElement)));
if (elementNode != null) {
elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED);
}
}
}
} else if (attribute.getInputName().length() == 0) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeMissingInputNameError, getName(attribute, inputElement)));
if (elementNode != null) {
elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED);
}
} else if (attribute.getInputTag().equals(Tag.OTHER) && Tag.fromLabel(attribute.getInputName()) != null) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_attributeReservedInputNameError, getName(attribute, inputElement)));
if (elementNode != null) {
elementNode.attributes.get(i).tagText.setBackground(COLOR_LIGHT_RED);
}
} else {
if (elementNode != null) {
elementNode.attributes.get(i).tagText.setBackground(fBGColor);
}
}
}
}
if (inputElement.getChildElements() != null) {
for (CustomXmlInputElement child : inputElement.getChildElements()) {
ElementNode childElementNode = null;
if (selectedElement != null && selectedElement.inputElement.equals(child)) {
childElementNode = selectedElement;
}
if (childElementNode != null) {
childElementNode.elementNameText.setBackground(fBGColor);
}
}
for (int i = 0; i < inputElement.getChildElements().size(); i++) {
CustomXmlInputElement child = inputElement.getChildElements().get(i);
ElementNode childElementNode = null;
if (selectedElement != null && selectedElement.inputElement.equals(child)) {
childElementNode = selectedElement;
}
if (child.getElementName().length() == 0) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementMissingNameError, getName(child)));
if (childElementNode != null) {
childElementNode.elementNameText.setBackground(COLOR_LIGHT_RED);
}
} else {
boolean duplicate = false;
for (int j = i + 1; j < inputElement.getChildElements().size(); j++) {
CustomXmlInputElement otherChild = inputElement.getChildElements().get(j);
if (otherChild.getElementName().equals(child.getElementName())) {
duplicate = true;
ElementNode otherChildElementNode = null;
if (selectedElement != null && selectedElement.inputElement.equals(otherChild)) {
otherChildElementNode = selectedElement;
}
if (otherChildElementNode != null) {
otherChildElementNode.elementNameText.setBackground(COLOR_LIGHT_RED);
}
}
}
if (duplicate) {
errors.add(NLS.bind(Messages.CustomXmlParserInputWizardPage_elementDuplicateNameError, getName(child)));
if (childElementNode != null) {
childElementNode.elementNameText.setBackground(COLOR_LIGHT_RED);
}
}
}
errors.addAll(validateElement(child));
}
}
return errors;
}
Aggregations