This commit is contained in:
jstaerk
2024-12-07 10:35:43 +01:00
parent c9853c097d
commit 98f0f140aa
4 changed files with 63 additions and 59 deletions

View File

@@ -1,12 +1,6 @@
595
591
577
575
573
601
2.15.1 2.15.1
======= =======
- #566 Failed to parse PDF - Could not reproduce the invoice - #566 Failed to parse PDF - Could not reproduce the invoice
? be able to access ID in error message ? be able to access ID in error message
- closes #579 prepaidamount is only read in UBL - closes #579 prepaidamount is only read in UBL
@@ -18,6 +12,13 @@
- allow jackson to run over more classes, e.g., DirectDebit, bean contructor for direct debit - allow jackson to run over more classes, e.g., DirectDebit, bean contructor for direct debit
- allow json includedNotes - allow json includedNotes
- support importing duePayableAmount - support importing duePayableAmount
- #595 Treat all fatal XR schematron rules as errors, not as warnings.
- #591 Import IncludedNotes on item extraction
- #577 dom4j: exclude all (optional) dependencies to avoid potential conflicts.
- #575 Fix compilation problems.
- #573 Feature/category code
- #601 exceptions in metrics
- #606 also parse BT-25
2.15.0 2.15.0

View File

@@ -808,6 +808,7 @@ public class ZUGFeRDInvoiceImporter {
} else { } else {
zpp.setDespatchAdviceReferencedDocumentID(extractString("//*[local-name()=\"DespatchDocumentReference\"]/*[local-name()=\"ID\"]")); zpp.setDespatchAdviceReferencedDocumentID(extractString("//*[local-name()=\"DespatchDocumentReference\"]/*[local-name()=\"ID\"]"));
} }
zpp.setInvoiceReferencedDocumentID(extractString("//*[local-name()=\"InvoiceReferencedDocument\"]/*[local-name()=\"IssuerAssignedID\"]|//*[local-name()=\"BillingReference\"]/*[local-name()=\"InvoiceDocumentReference\"]/*[local-name()=\"ID\"]"));
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim()); zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
@@ -929,6 +930,7 @@ public class ZUGFeRDInvoiceImporter {
} }
TransactionCalculator tc = new TransactionCalculator(zpp); TransactionCalculator tc = new TransactionCalculator(zpp);
String expectedStringTotalGross = tc.getGrandTotal() String expectedStringTotalGross = tc.getGrandTotal()
.subtract(Objects.requireNonNullElse(zpp.getTotalPrepaidAmount(), BigDecimal.ZERO)).toPlainString(); .subtract(Objects.requireNonNullElse(zpp.getTotalPrepaidAmount(), BigDecimal.ZERO)).toPlainString();

View File

@@ -539,6 +539,7 @@ public class ZF2PushTest extends TestCase {
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16))) .addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14)) .addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE) .setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
.setInvoiceReferencedDocumentID("abc123")
); );
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
@@ -582,6 +583,7 @@ public class ZF2PushTest extends TestCase {
try { try {
Invoice i = zii.extractInvoice(); Invoice i = zii.extractInvoice();
assertEquals("abc123", i.getInvoiceReferencedDocumentID());
assertEquals("4304171000002", i.getRecipient().getGlobalID()); assertEquals("4304171000002", i.getRecipient().getGlobalID());
assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID()); assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID());
assertEquals(orgID, i.getSender().getID()); assertEquals(orgID, i.getSender().getID());

View File

@@ -1,4 +1,5 @@
package org.mustangproject.validator; package org.mustangproject.validator;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringReader; import java.io.StringReader;
@@ -69,15 +70,13 @@ public class XMLValidator extends Validator {
final ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(9) final ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(9)
.setPart(EPart.fx); .setPart(EPart.fx);
try (final StringWriter sw = new StringWriter(); try (final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw)) final PrintWriter pw = new PrintWriter(sw)) {
{ e.printStackTrace(pw);
e.printStackTrace(pw); vri.setStacktrace(sw.toString());
vri.setStacktrace(sw.toString()); context.addResultItem(vri);
context.addResultItem(vri); } catch (IOException ex) {
throw new UncheckedIOException(ex);
} }
catch (IOException ex) {
throw new UncheckedIOException (ex);
}
} }
} }
@@ -125,9 +124,9 @@ public class XMLValidator extends Validator {
if (zfXML.isEmpty()) { if (zfXML.isEmpty()) {
final ValidationResultItem res = new ValidationResultItem(ESeverity.exception, final ValidationResultItem res = new ValidationResultItem(ESeverity.exception,
"XML data not found in " + filename "XML data not found in " + filename
+ ": did you specify a pdf or xml file and does the xml file contain an embedded XML file?") + ": did you specify a pdf or xml file and does the xml file contain an embedded XML file?")
.setSection(3); .setSection(3);
context.addResultItem(res); context.addResultItem(res);
} else { } else {
@@ -170,7 +169,7 @@ public class XMLValidator extends Validator {
// Create XPath object // Create XPath object
final XPath xpath = xpathFactory.newXPath(); final XPath xpath = xpathFactory.newXPath();
final XPathExpression expr = xpath.compile( final XPathExpression expr = xpath.compile(
"(//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/*[local-name()=\"ID\"])/text()|//*[local-name()=\"CustomizationID\"]/text()"); "(//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/*[local-name()=\"ID\"])/text()|//*[local-name()=\"CustomizationID\"]/text()");
// evaluate expression result on XML document // evaluate expression result on XML document
ndList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); ndList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
@@ -191,7 +190,7 @@ public class XMLValidator extends Validator {
boolean isExtended = false; boolean isExtended = false;
boolean isXRechnung = false; boolean isXRechnung = false;
String currentZFVersionDir = "ZF_232"; String currentZFVersionDir = "ZF_232";
int mainSchematronSectionErrorTypeCode=4; int mainSchematronSectionErrorTypeCode = 4;
String xsltFilename = null; String xsltFilename = null;
// urn:ferd:CrossIndustryDocument:invoice:1p0:extended, // urn:ferd:CrossIndustryDocument:invoice:1p0:extended,
// urn:ferd:CrossIndustryDocument:invoice:1p0:comfort, // urn:ferd:CrossIndustryDocument:invoice:1p0:comfort,
@@ -224,7 +223,7 @@ public class XMLValidator extends Validator {
isBasic = false;// basicwl also contains the string basic... isBasic = false;// basicwl also contains the string basic...
} }
isEN16931 = matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931") isEN16931 = matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931")
|| matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017"); || matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017");
isExtended = context.getProfile().contains("extended"); isExtended = context.getProfile().contains("extended");
isXRechnung = context.getProfile().contains("xrechnung"); isXRechnung = context.getProfile().contains("xrechnung");
@@ -269,16 +268,16 @@ public class XMLValidator extends Validator {
// saxon java net.sf.saxon.Transform -o tcdl2.0.tsdtf.sch.tmp.xsl -s // saxon java net.sf.saxon.Transform -o tcdl2.0.tsdtf.sch.tmp.xsl -s
// tcdl2.0.tsdtf.sch iso_svrl.xsl // tcdl2.0.tsdtf.sch iso_svrl.xsl
} else if (root.getLocalName().equalsIgnoreCase("Invoice") || root.getLocalName().equalsIgnoreCase("CreditNote") ) { } else if (root.getLocalName().equalsIgnoreCase("Invoice") || root.getLocalName().equalsIgnoreCase("CreditNote")) {
context.setGeneration("2"); context.setGeneration("2");
context.setFormat("UBL"); context.setFormat("UBL");
isXRechnung = context.getProfile().contains("xrechnung"); isXRechnung = context.getProfile().contains("xrechnung");
// UBL // UBL
LOGGER.debug("UBL"); LOGGER.debug("UBL");
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "UBL_21/maindoc/UBL-"+root.getLocalName()+"-2.1.xsd", 18, EPart.fx); validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "UBL_21/maindoc/UBL-" + root.getLocalName() + "-2.1.xsd", 18, EPart.fx);
xsltFilename = "/xslt/en16931schematron/EN16931-UBL-validation.xslt"; xsltFilename = "/xslt/en16931schematron/EN16931-UBL-validation.xslt";
mainSchematronSectionErrorTypeCode=24; mainSchematronSectionErrorTypeCode = 24;
if (isXRechnung) { if (isXRechnung) {
validateSchematron(zfXML, xsltFilename, 24, ESeverity.error); validateSchematron(zfXML, xsltFilename, 24, ESeverity.error);
@@ -287,14 +286,14 @@ public class XMLValidator extends Validator {
XRechnung is a EN16931 subset so the validation vis a vis FACTUR-X_EN16931.xslt=schematron also has to pass XRechnung is a EN16931 subset so the validation vis a vis FACTUR-X_EN16931.xslt=schematron also has to pass
* */ * */
//validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_211/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx); //validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_211/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx);
String xrVersion=context.getProfile().substring(context.getProfile().length()-3).replace(".",""); String xrVersion = context.getProfile().substring(context.getProfile().length() - 3).replace(".", "");
if (!xrVersion.equals("12")&&!xrVersion.equals("20")&&!xrVersion.equals("21")&&!xrVersion.equals("22")&&!xrVersion.equals("23")&&!xrVersion.equals("30")) { if (!xrVersion.equals("12") && !xrVersion.equals("20") && !xrVersion.equals("21") && !xrVersion.equals("22") && !xrVersion.equals("23") && !xrVersion.equals("30")) {
throw new Exception("Unsupported XR version"); throw new Exception("Unsupported XR version");
} }
LOGGER.debug("is XRechnung v"+xrVersion); LOGGER.debug("is XRechnung v" + xrVersion);
xsltFilename = "/xslt/XR_"+xrVersion+"/XRechnung-UBL-validation.xslt"; xsltFilename = "/xslt/XR_" + xrVersion + "/XRechnung-UBL-validation.xslt";
XrechnungSeverity = ESeverity.error; XrechnungSeverity = ESeverity.error;
mainSchematronSectionErrorTypeCode=27; mainSchematronSectionErrorTypeCode = 27;
} }
@@ -302,58 +301,58 @@ public class XMLValidator extends Validator {
context.setGeneration("1"); context.setGeneration("1");
// //
if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic")) if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort")) && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) { && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type") context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type")
.setSection(25).setPart(EPart.fx)); .setSection(25).setPart(EPart.fx));
} }
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_10/ZUGFeRD1p0.xsd", 18, EPart.fx); validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_10/ZUGFeRD1p0.xsd", 18, EPart.fx);
xsltFilename = "/xslt/ZUGFeRD_1p0.xslt"; xsltFilename = "/xslt/ZUGFeRD_1p0.xslt";
} else { // unknown document root } else { // unknown document root
context.addResultItem(new ValidationResultItem(ESeverity.fatal, "Unsupported root element") context.addResultItem(new ValidationResultItem(ESeverity.fatal, "Unsupported root element")
.setSection(3).setPart(EPart.fx)); .setSection(3).setPart(EPart.fx));
} }
if (context.getFormat().equals("CII")) { if (context.getFormat().equals("CII")) {
if (context.getGeneration().equals("2")) { if (context.getGeneration().equals("2")) {
if ((!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:minimum")) if ((!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:minimum"))
&& (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:minimum")) && (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:minimum"))
&& (!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:basicwl")) && (!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:basicwl"))
&& (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:basicwl")) && (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:basicwl"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic")) && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic")) && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017")) && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended")) && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"))) { && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"))) {
context.addResultItem( context.addResultItem(
new ValidationResultItem(ESeverity.error, "Unsupported profile type " + context.getProfile()) new ValidationResultItem(ESeverity.error, "Unsupported profile type " + context.getProfile())
.setSection(25).setPart(EPart.fx)); .setSection(25).setPart(EPart.fx));
} }
} else /** v1 */ { } else /** v1 */ {
if (isOrderX) { if (isOrderX) {
//order-x 1.0 //order-x 1.0
if ((!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:basic")) if ((!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:comfort")) && (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:extended"))) { && (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:extended"))) {
//zf 1.0 //zf 1.0
context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type") context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type")
.setSection(25).setPart(EPart.fx)); .setSection(25).setPart(EPart.fx));
} }
} else if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic")) } else if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort")) && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) { && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) {
//zf 1.0 //zf 1.0
context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type") context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type")
.setSection(25).setPart(EPart.fx)); .setSection(25).setPart(EPart.fx));
} }
} }
} }
if (xsltFilename!=null) { if (xsltFilename != null) {
// main schematron validation // main schematron validation
validateSchematron(zfXML, xsltFilename, mainSchematronSectionErrorTypeCode, ESeverity.error); validateSchematron(zfXML, xsltFilename, mainSchematronSectionErrorTypeCode, ESeverity.error);
@@ -362,7 +361,7 @@ public class XMLValidator extends Validator {
if (context.getFormat().equals("CII")) { if (context.getFormat().equals("CII")) {
if (context.getGeneration().equals("2") if (context.getGeneration().equals("2")
&& (isBasic || isEN16931 || isXRechnung)) { && (isBasic || isEN16931 || isXRechnung)) {
//additionally validate against CEN //additionally validate against CEN
validateSchematron(zfXML, "/xslt/en16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error); validateSchematron(zfXML, "/xslt/en16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error);
if (!disableNotices || XrechnungSeverity != ESeverity.notice) { if (!disableNotices || XrechnungSeverity != ESeverity.notice) {
@@ -376,7 +375,7 @@ public class XMLValidator extends Validator {
throw er; throw er;
} catch (final Exception e) { } catch (final Exception e) {
final ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(22) final ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(22)
.setPart(EPart.fx); .setPart(EPart.fx);
final StringWriter sw = new StringWriter(); final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw); final PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw); e.printStackTrace(pw);
@@ -388,8 +387,8 @@ public class XMLValidator extends Validator {
final long endTime = Calendar.getInstance().getTimeInMillis(); final long endTime = Calendar.getInstance().getTimeInMillis();
context.addCustomXML("<info><version>" + ((context.getGeneration() != null) ? context.getGeneration() : "invalid") context.addCustomXML("<info><version>" + ((context.getGeneration() != null) ? context.getGeneration() : "invalid")
+ "</version><profile>" + ((context.getProfile() != null) ? context.getProfile() : "invalid") + + "</version><profile>" + ((context.getProfile() != null) ? context.getProfile() : "invalid") +
"</profile><validator version=\"" + XMLValidator.class.getPackage().getImplementationVersion() + "\"></validator><rules><fired>" + firedRules + "</fired><failed>" + failedRules + "</failed></rules>" + "<duration unit=\"ms\">" + (endTime - startXMLTime) + "</duration></info>"); "</profile><validator version=\"" + XMLValidator.class.getPackage().getImplementationVersion() + "\"></validator><rules><fired>" + firedRules + "</fired><failed>" + failedRules + "</failed></rules>" + "<duration unit=\"ms\">" + (endTime - startXMLTime) + "</duration></info>");
} }
@@ -434,7 +433,7 @@ public class XMLValidator extends Validator {
final SchematronOutputType sout; final SchematronOutputType sout;
try { try {
sout = aResSCH sout = aResSCH
.applySchematronValidationToSVRL(new StreamSource(new StringReader(xml))); .applySchematronValidationToSVRL(new StreamSource(new StringReader(xml)));
} catch (final Exception e) { } catch (final Exception e) {
throw new IrrecoverableValidationError(e.getMessage()); throw new IrrecoverableValidationError(e.getMessage());
} }
@@ -471,7 +470,7 @@ public class XMLValidator extends Validator {
if (defaultSeverity == ESeverity.notice) { if (defaultSeverity == ESeverity.notice) {
severity = defaultSeverity; severity = defaultSeverity;
} else if (currentFailNode.getAttributes().getNamedItem("flag") != null } else if (currentFailNode.getAttributes().getNamedItem("flag") != null
&& currentFailNode.getAttributes().getNamedItem("flag").getNodeValue().equals("warning")) { && currentFailNode.getAttributes().getNamedItem("flag").getNodeValue().equals("warning")) {
// the XR issues warnings with flag=warning // the XR issues warnings with flag=warning
severity = ESeverity.warning; severity = ESeverity.warning;
} else { } else {
@@ -493,8 +492,8 @@ public class XMLValidator extends Validator {
LOGGER.info("FailedAssert ", thisFailText); LOGGER.info("FailedAssert ", thisFailText);
context.addResultItem(new ValidationResultItem(severity, thisFailText + thisFailIDStr + " from " + xsltFilename + ")") context.addResultItem(new ValidationResultItem(severity, thisFailText + thisFailIDStr + " from " + xsltFilename + ")")
.setLocation(thisFailLocation).setCriterion(thisFailTest).setSection(section).setID(thisFailID) .setLocation(thisFailLocation).setCriterion(thisFailTest).setSection(section).setID(thisFailID)
.setPart(EPart.fx)); .setPart(EPart.fx));
failedRules++; failedRules++;
} }
@@ -525,7 +524,7 @@ public class XMLValidator extends Validator {
if (firedRules == 0) { if (firedRules == 0) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "No rules matched, XML to minimal?").setSection(26) context.addResultItem(new ValidationResultItem(ESeverity.error, "No rules matched, XML to minimal?").setSection(26)
.setPart(EPart.fx)); .setPart(EPart.fx));
} }
// for (String currentString : sout.getText()) { // for (String currentString : sout.getText()) {