Skip to content

Commit ca4c3bb

Browse files
Egor MartsynkovskyiText-CI
authored andcommitted
Add support of attr() with type for url and string
Add support of attr() with fallback for url and string Add support of attr() in target-counter Add tests DEVSIX-2994
1 parent e6d8afa commit ca4c3bb

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed

styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/CommonCssConstants.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ public class CommonCssConstants {
8484
*/
8585
public static final String ALIGN_SELF = "align-self";
8686

87+
/**
88+
* The constant ATTRIBUTE.
89+
*/
90+
public static final String ATTRIBUTE = "attr";
91+
8792
/**
8893
* The Constant BACKGROUND.
8994
*/
@@ -1427,6 +1432,11 @@ public class CommonCssConstants {
14271432
*/
14281433
public static final String STRETCH = "stretch";
14291434

1435+
/**
1436+
* The Constant STRING.
1437+
*/
1438+
public static final String STRING = "string";
1439+
14301440
/**
14311441
* The Constant THICK.
14321442
*/
@@ -1760,6 +1770,11 @@ public class CommonCssConstants {
17601770
*/
17611771
public static final String TARGET = "target";
17621772

1773+
/**
1774+
* The Constant URL.
1775+
*/
1776+
public static final String URL = "url";
1777+
17631778
/**
17641779
* The Constant VALID.
17651780
*/

styled-xml-parser/src/main/java/com/itextpdf/styledxmlparser/css/util/CssUtils.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ This file is part of the iText (R) project.
5353
import com.itextpdf.styledxmlparser.css.parse.CssDeclarationValueTokenizer.Token;
5454
import com.itextpdf.styledxmlparser.css.parse.CssDeclarationValueTokenizer.TokenType;
5555

56+
import java.util.regex.Matcher;
57+
import java.util.regex.Pattern;
5658
import java.util.ArrayList;
5759
import java.util.List;
5860

@@ -72,6 +74,8 @@ public class CssUtils {
7274

7375
private static final Logger logger = LoggerFactory.getLogger(CssUtils.class);
7476

77+
private static final int QUANTITY_OF_PARAMS_WITH_FALLBACK_OR_TYPE = 2;
78+
7579
/**
7680
* Creates a new {@link CssUtils} instance.
7781
*/
@@ -623,6 +627,45 @@ public static String extractUrl(final String url) {
623627
return str;
624628
}
625629

630+
/**
631+
* Parses string and return attribute value.
632+
*
633+
* @param attrStr the string contains attr() to extract attribute value
634+
* @param element the parentNode from which we extract information
635+
* @return the value of attribute
636+
*/
637+
public static String extractAttributeValue(final String attrStr, IElementNode element) {
638+
String attrValue = null;
639+
if (attrStr.startsWith(CommonCssConstants.ATTRIBUTE + '(')
640+
&& attrStr.length() > CommonCssConstants.ATTRIBUTE.length() + 2 && attrStr.endsWith(")")) {
641+
String fallback = null;
642+
String typeOfAttribute = null;
643+
final String stringToSplit = attrStr.substring(5, attrStr.length() - 1);
644+
final List<String> paramsWithFallback = splitString(stringToSplit, ',', new EscapeGroup('\"'),
645+
new EscapeGroup('\''));
646+
if (paramsWithFallback.size() > QUANTITY_OF_PARAMS_WITH_FALLBACK_OR_TYPE) {
647+
return null;
648+
}
649+
if (paramsWithFallback.size() == QUANTITY_OF_PARAMS_WITH_FALLBACK_OR_TYPE) {
650+
fallback = extractFallback(paramsWithFallback.get(1));
651+
}
652+
final List<String> params = splitString(paramsWithFallback.get(0), ' ');
653+
if (params.size() > QUANTITY_OF_PARAMS_WITH_FALLBACK_OR_TYPE) {
654+
return null;
655+
} else if (params.size() == QUANTITY_OF_PARAMS_WITH_FALLBACK_OR_TYPE) {
656+
typeOfAttribute = extractTypeOfAttribute(params.get(1));
657+
if (typeOfAttribute == null) {
658+
return null;
659+
}
660+
}
661+
String attributeName = params.get(0);
662+
if (isAttributeNameValid(attributeName)) {
663+
attrValue = getAttributeValue(attributeName, typeOfAttribute, fallback, element);
664+
}
665+
}
666+
return attrValue;
667+
}
668+
626669
/**
627670
* Checks if a data is base 64 encoded.
628671
*
@@ -810,4 +853,42 @@ private static boolean addRange(RangeBuilder builder, String left, String right)
810853
builder.addRange(l, r);
811854
return true;
812855
}
856+
857+
private static boolean isAttributeNameValid(String attributeName) {
858+
return !(attributeName.contains("'") || attributeName.contains("\"") || attributeName.contains("(")
859+
|| attributeName.contains(")"));
860+
}
861+
862+
private static String extractFallback(String fallbackString) {
863+
String tmpString;
864+
if ((fallbackString.startsWith("'") && fallbackString.endsWith("'")) || (fallbackString.startsWith("\"")
865+
&& fallbackString.endsWith("\""))) {
866+
tmpString = fallbackString.substring(1, fallbackString.length() - 1);
867+
} else {
868+
tmpString = fallbackString;
869+
}
870+
return extractUrl(tmpString);
871+
}
872+
873+
private static String extractTypeOfAttribute(String typeString) {
874+
if (typeString.equals(CommonCssConstants.URL) || typeString.equals(CommonCssConstants.STRING)) {
875+
return typeString;
876+
}
877+
return null;
878+
}
879+
880+
private static String getAttributeValue(final String attributeName, final String typeOfAttribute,
881+
final String fallback,
882+
IElementNode elementNode) {
883+
String returnString = elementNode.getAttribute(attributeName);
884+
if (CommonCssConstants.URL.equals(typeOfAttribute)) {
885+
returnString = returnString == null ? null : extractUrl(returnString);
886+
} else {
887+
returnString = returnString == null ? "" : returnString;
888+
}
889+
if (fallback != null && (returnString == null || returnString.isEmpty())) {
890+
returnString = fallback;
891+
}
892+
return returnString;
893+
}
813894
}

styled-xml-parser/src/test/java/com/itextpdf/styledxmlparser/css/util/CssUtilsTest.java

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ This file is part of the iText (R) project.
4747
import com.itextpdf.styledxmlparser.CommonAttributeConstants;
4848
import com.itextpdf.styledxmlparser.LogMessageConstant;
4949
import com.itextpdf.styledxmlparser.css.CommonCssConstants;
50+
import com.itextpdf.styledxmlparser.css.pseudo.CssPseudoElementNode;
5051
import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException;
5152
import com.itextpdf.styledxmlparser.jsoup.nodes.Element;
5253
import com.itextpdf.styledxmlparser.jsoup.parser.Tag;
54+
import com.itextpdf.styledxmlparser.node.IElementNode;
55+
import com.itextpdf.styledxmlparser.node.INode;
5356
import com.itextpdf.styledxmlparser.node.impl.jsoup.node.JsoupElementNode;
5457
import com.itextpdf.test.ExtendedITextTest;
5558
import com.itextpdf.test.annotations.LogMessage;
@@ -465,4 +468,129 @@ public void isNegativeValueTest() {
465468
Assert.assertTrue(CssUtils.isNegativeValue("-0.123"));
466469
Assert.assertTrue(CssUtils.isNegativeValue("-.34"));
467470
}
471+
472+
@Test
473+
public void testWrongAttrTest01() {
474+
String strToParse = "attr((href))";
475+
String result = CssUtils.extractAttributeValue(strToParse, null);
476+
Assert.assertNull(result);
477+
}
478+
479+
@Test
480+
public void testWrongAttrTest02() {
481+
String strToParse = "attr('href')";
482+
String result = CssUtils.extractAttributeValue(strToParse, null);
483+
Assert.assertNull(result);
484+
}
485+
486+
@Test
487+
public void testWrongAttrTest03() {
488+
String strToParse = "attrrname)";
489+
String result = CssUtils.extractAttributeValue(strToParse, null);
490+
Assert.assertNull(result);
491+
}
492+
493+
@Test
494+
public void testExtractingAttrTest01() {
495+
IElementNode iNode = new CssPseudoElementNode(null, "url");
496+
String strToParse = "attr(url)";
497+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
498+
Assert.assertEquals("", result);
499+
}
500+
501+
@Test
502+
public void testExtractingAttrTest02() {
503+
IElementNode iNode = new CssPseudoElementNode(null, "test");
504+
String strToParse = "attr(url url)";
505+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
506+
Assert.assertNull(result);
507+
}
508+
509+
@Test
510+
public void testExtractingAttrTest03() {
511+
IElementNode iNode = new CssPseudoElementNode(null, "test");
512+
String strToParse = "attr(url url,#one)";
513+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
514+
Assert.assertEquals("#one", result);
515+
}
516+
517+
@Test
518+
public void testExtractingAttrTest04() {
519+
IElementNode iNode = new CssPseudoElementNode(null, "test");
520+
String strToParse = "attr()";
521+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
522+
Assert.assertNull(result);
523+
}
524+
525+
@Test
526+
public void testExtractingAttrTest05() {
527+
IElementNode iNode = new CssPseudoElementNode(null, "test");
528+
String strToParse = "attr('\')";
529+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
530+
Assert.assertNull(result);
531+
}
532+
533+
@Test
534+
public void testExtractingAttrTest06() {
535+
IElementNode iNode = new CssPseudoElementNode(null, "test");
536+
String strToParse = "attr(str,\"hey\")";
537+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
538+
Assert.assertEquals("hey", result);
539+
}
540+
541+
@Test
542+
public void testExtractingAttrTest07() {
543+
IElementNode iNode = new CssPseudoElementNode(null, "test");
544+
String strToParse = "attr(str string)";
545+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
546+
Assert.assertEquals("", result);
547+
}
548+
549+
@Test
550+
public void testExtractingAttrTest08() {
551+
IElementNode iNode = new CssPseudoElementNode(null, "test");
552+
String strToParse = "attr(str string,\"value\")";
553+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
554+
Assert.assertEquals("value", result);
555+
}
556+
557+
@Test
558+
public void testExtractingAttrTest09() {
559+
IElementNode iNode = new CssPseudoElementNode(null, "test");
560+
String strToParse = "attr(str string,\"val,ue\")";
561+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
562+
Assert.assertEquals("val,ue", result);
563+
}
564+
565+
@Test
566+
public void testExtractingAttrTest10() {
567+
IElementNode iNode = new CssPseudoElementNode(null, "test");
568+
String strToParse = "attr(str string,'val,ue')";
569+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
570+
Assert.assertEquals("val,ue", result);
571+
}
572+
573+
@Test
574+
public void testExtractingAttrTest11() {
575+
IElementNode iNode = new CssPseudoElementNode(null, "test");
576+
String strToParse = "attr(name, \"value\", \"value\", \"value\")";
577+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
578+
Assert.assertNull(result);
579+
}
580+
581+
@Test
582+
public void wrongAttributeTypeTest() {
583+
IElementNode iNode = new CssPseudoElementNode(null, "test");
584+
String strToParse = "attr(str mem)";
585+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
586+
Assert.assertNull(result);
587+
}
588+
589+
@Test
590+
public void wrongParamsInAttrFunctionTest() {
591+
IElementNode iNode = new CssPseudoElementNode(null, "test");
592+
String strToParse = "attr(str mem lol)";
593+
String result = CssUtils.extractAttributeValue(strToParse, iNode);
594+
Assert.assertNull(result);
595+
}
468596
}

0 commit comments

Comments
 (0)