Skip to content

Commit

Permalink
MID-9461: fix writing of CDATA to xml when html format is used
Browse files Browse the repository at this point in the history
  • Loading branch information
skublik committed Mar 18, 2024
1 parent a1dd077 commit edfd224
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,19 @@ private void writePrimitiveWithType(PrimitiveXNodeImpl<?> xprim, Element parentE
} else {
// not ItemType nor QName
String value = xprim.getGuessedFormattedValue();
String fixedValue = SerializationOptions.isEscapeInvalidCharacters(serializationOptions) ?
DOMUtil.escapeInvalidXmlCharsIfPresent(value) : value;
if (asAttribute) {
DOMUtil.setAttributeValue(parentElement, elementOrAttributeName.getLocalPart(), fixedValue);

if (QNameUtil.match(elementOrAttributeName, DOMUtil.SCRIPT_CODE_ELEMENT_NAME)
&& DOMUtil.containsHTML(value)) {
DOMUtil.setElementTextContentWithCDATAPrefix(element, value);
} else {
DOMUtil.setElementTextContent(element, fixedValue);

String fixedValue = SerializationOptions.isEscapeInvalidCharacters(serializationOptions) ?
DOMUtil.escapeInvalidXmlCharsIfPresent(value) : value;
if (asAttribute) {
DOMUtil.setAttributeValue(parentElement, elementOrAttributeName.getLocalPart(), fixedValue);
} else {
DOMUtil.setElementTextContent(element, fixedValue);
}
}
}
}
Expand Down
86 changes: 58 additions & 28 deletions infra/prism-impl/src/main/resources/xml/ns/test/foo-1.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,32 @@
-->

<xsd:schema targetNamespace="http://midpoint.evolveum.com/xml/ns/test/foo-1.xsd"
xmlns:tns="http://midpoint.evolveum.com/xml/ns/test/foo-1.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://prism.evolveum.com/xml/ns/public/annotation-3"
xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
xmlns:ft="http://midpoint.evolveum.com/xml/ns/test/foo-types-1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
elementFormDefault="qualified"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="2.0">
xmlns:tns="http://midpoint.evolveum.com/xml/ns/test/foo-1.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://prism.evolveum.com/xml/ns/public/annotation-3"
xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"
xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
xmlns:ft="http://midpoint.evolveum.com/xml/ns/test/foo-types-1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
elementFormDefault="qualified"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="2.0">

<xsd:annotation>
<xsd:documentation>
Testing schema for Prism framework
</xsd:documentation>
<xsd:appinfo>
<jaxb:globalBindings>
<xjc:typeSubstitution type="complex" />
<xjc:serializable uid="201202081233" />
<xjc:typeSubstitution type="complex"/>
<xjc:serializable uid="201202081233"/>
</jaxb:globalBindings>
</xsd:appinfo>
</xsd:annotation>

<xsd:import namespace="http://prism.evolveum.com/xml/ns/public/query-3" schemaLocation="http://prism.evolveum.com/xml/ns/public/query-3" />
<xsd:import namespace="http://prism.evolveum.com/xml/ns/public/query-3" schemaLocation="http://prism.evolveum.com/xml/ns/public/query-3"/>

<xsd:import namespace="http://prism.evolveum.com/xml/ns/public/types-3" schemaLocation="http://prism.evolveum.com/xml/ns/public/types-3">
<xsd:annotation>
Expand Down Expand Up @@ -169,17 +169,17 @@
<!-- element that has different names in XML/JSON/YAML and in java bean -->
<xsd:element name="special" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<!-- single-occurrence container -->
<xsd:element name="singleActivation" type="tns:ActivationType" minOccurs="0" />
<xsd:element name="singleActivation" type="tns:ActivationType" minOccurs="0"/>
<!-- multi-occurrence container -->
<xsd:element name="multiActivation" type="tns:ActivationType" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="multiActivation" type="tns:ActivationType" minOccurs="0" maxOccurs="unbounded"/>
<!-- multi-occurrence container -->
<xsd:element name="multiActivationCopy" type="tns:ActivationType" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="multiActivationCopy" type="tns:ActivationType" minOccurs="0" maxOccurs="unbounded"/>
<!-- single-occurrence structured property (not a container) -->
<xsd:element name="singleConstruction" type="tns:AccountConstructionType" minOccurs="0" />
<xsd:element name="singleConstruction" type="tns:AccountConstructionType" minOccurs="0"/>
<!-- multi-occurrence container -->
<xsd:element name="multiConstruction" type="tns:AccountConstructionType" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="multiConstruction" type="tns:AccountConstructionType" minOccurs="0" maxOccurs="unbounded"/>
<!-- multi-occurrence container -->
<xsd:element name="multiConstructionCopy" type="tns:AccountConstructionType" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="multiConstructionCopy" type="tns:AccountConstructionType" minOccurs="0" maxOccurs="unbounded"/>

</xsd:sequence>
</xsd:extension>
Expand Down Expand Up @@ -361,18 +361,18 @@
<xsd:complexType name="EventHandlerType">
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
<xsd:element name="handler" type="tns:EventHandlerType" abstract="true" />
<xsd:element name="handler" type="tns:EventHandlerType" abstract="true"/>

<xsd:complexType name="EventHandlerChainType">
<xsd:complexContent>
<xsd:extension base="tns:EventHandlerType">
<xsd:sequence>
<xsd:element ref="tns:handler" minOccurs="0" maxOccurs="unbounded" />
<xsd:element ref="tns:handler" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="handlerChain" type="tns:EventHandlerChainType" substitutionGroup="tns:handler" />
<xsd:element name="handlerChain" type="tns:EventHandlerChainType" substitutionGroup="tns:handler"/>

<xsd:complexType name="EventCategoryFilterType">
<xsd:complexContent>
Expand All @@ -383,7 +383,7 @@
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="categoryFilter" type="tns:EventCategoryFilterType" substitutionGroup="tns:handler" />
<xsd:element name="categoryFilter" type="tns:EventCategoryFilterType" substitutionGroup="tns:handler"/>

<xsd:complexType name="EventStatusFilterType">
<xsd:complexContent>
Expand All @@ -394,7 +394,7 @@
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="statusFilter" type="tns:EventStatusFilterType" substitutionGroup="tns:handler" />
<xsd:element name="statusFilter" type="tns:EventStatusFilterType" substitutionGroup="tns:handler"/>

<xsd:complexType name="EventOperationFilterType">
<xsd:complexContent>
Expand All @@ -405,7 +405,7 @@
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="operationFilter" type="tns:EventOperationFilterType" substitutionGroup="tns:handler" />
<xsd:element name="operationFilter" type="tns:EventOperationFilterType" substitutionGroup="tns:handler"/>

<xsd:complexType name="FooValueMetadataType">
<xsd:annotation>
Expand All @@ -418,5 +418,35 @@
<xsd:element name="test" type="xsd:string" minOccurs="0"/>
</xsd:sequence -->
</xsd:complexType>
<xsd:element name="fooValueMetadataType" type="tns:FooValueMetadataType" />
<xsd:element name="fooValueMetadataType" type="tns:FooValueMetadataType"/>

<xsd:complexType name="MessageTemplateType">
<xsd:complexContent>
<xsd:extension base="tns:ObjectType">
<xsd:sequence>
<xsd:element name="defaultContent" type="tns:MessageTemplateContentType" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="messageTemplate" type="tns:MessageTemplateType"/>

<xsd:complexType name="MessageTemplateContentType">
<xsd:sequence>
<xsd:element name="bodyExpression" type="tns:ExpressionType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ExpressionType">
<xsd:sequence>
<xsd:element name="script" type="tns:ScriptExpressionEvaluatorType"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ScriptExpressionEvaluatorType">
<xsd:sequence>
<xsd:element name="code" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>

</xsd:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,13 @@
</xsd:annotation>
</xsd:element>

<xsd:element name="code" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<a:maxOccurs>1</a:maxOccurs>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>

</xsd:schema>

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static com.evolveum.midpoint.prism.PrismInternalTestUtil.USER_JACK_FILE_BASENAME;
import static com.evolveum.midpoint.prism.util.PrismTestUtil.createDefaultParsingContext;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;

import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -17,6 +18,8 @@
import com.evolveum.midpoint.prism.ParserFileSource;
import com.evolveum.midpoint.prism.impl.lex.LexicalProcessor;
import com.evolveum.midpoint.prism.impl.lex.dom.DomLexicalProcessor;
import com.evolveum.midpoint.prism.xnode.RootXNode;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.DebugUtil;

import org.testng.annotations.Test;
Expand All @@ -31,6 +34,8 @@
import com.evolveum.midpoint.prism.impl.xnode.RootXNodeImpl;
import com.evolveum.midpoint.prism.impl.xnode.XNodeImpl;

import javax.xml.namespace.QName;

/**
* @author semancik
*
Expand All @@ -40,6 +45,8 @@ public class TestDomParser extends AbstractLexicalProcessorTest {
private static final String OBJECTS_XML_1_NO_NS = "objects-xml-1-no-ns";
private static final String OBJECTS_XML_2_NS = "objects-xml-2-ns";

private static final String MESSAGE_TEMPLATE = "messageTemplate";

@Override
protected String getSubdirName() {
return "xml";
Expand Down Expand Up @@ -149,6 +156,24 @@ public void testParseObjects_xml_2_Ns() throws Exception {
assertEquals("Nodes are different", nodesStandard, nodes);
}

@Test
public void testWriteScriptCode() throws Exception {
// GIVEN
LexicalProcessor<String> lexicalProcessor = createLexicalProcessor();
RootXNodeImpl xnode = lexicalProcessor.read(new ParserFileSource(getFile(MESSAGE_TEMPLATE)), createDefaultParsingContext());
((MapXNodeImpl)((MapXNodeImpl)((MapXNodeImpl)((MapXNodeImpl) xnode.getSubnode()).get("defaultContent"))
.get("bodyExpression"))
.get("script"))
.get("code").setTypeQName(DOMUtil.XSD_STRING);

// WHEN (parse to xnode)
String xml = lexicalProcessor.write(xnode, null);

// THEN
assertTrue(xml.contains("<code><![CDATA["));
assertTrue(xml.contains("]]></code>"));
}


private void validateSchemaCompliance(String xmlString, PrismContext prismContext) throws SAXException, IOException {
// Document xmlDocument = DOMUtil.parseDocument(xmlString);
Expand Down
49 changes: 49 additions & 0 deletions infra/prism-impl/src/test/resources/common/xml/messageTemplate.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<messageTemplate xmlns='http://midpoint.evolveum.com/xml/ns/test/foo-1.xsd'>
<name>message-template</name>
<defaultContent>
<bodyExpression>
<script>
<code><![CDATA[
<html>
<head>
<style>
/* Use your CSS styles as needed */
div.footer {
height: 64px;
width: 100%;
border-top: solid thin;
margin-left: auto;
margin-right: auto;
background-color: ivory;
}
body {
font: normal 14px Roboto, sans-serif;
}
.center {
text-align: center;
}
</style>
</head>
<body>
<h1>User Modification Notification</h1>
<p>User <b>$!event.requesteeDisplayName</b> ($event.requesteeName) was <b>modified</b> (status: $event.statusAsText)</p>
<p>The user modification was requested by $event.requesterDisplayName ($event.requesterName)</p>
<div class="footer">
<img src="http://localhost/midpoint/static-web/example-logo-s.png" alt="[Example logo]" width="64" height="64" style="float:left;"/>
<p class="center">This notification has been from an unmonitored mailbox.<br/>
<b>IT Department of Example, Inc.</b>
</p>
</div>
</body>
</html>
]]></code>
</script>
</bodyExpression>
</defaultContent>
</messageTemplate>
49 changes: 49 additions & 0 deletions infra/util/src/main/java/com/evolveum/midpoint/util/DOMUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ public class DOMUtil {
public static final QName WSDL_ATTR_LOCATION = new QName(NS_WSDL, "location",
NS_WSDL_SCHEMA_PREFIX);


public static final QName SCRIPT_CODE_ELEMENT_NAME = new QName("code");

private static final String RANDOM_ATTR_PREFIX_PREFIX = "qn";
private static final int RANDOM_ATTR_PREFIX_RND = 1000;
private static final int RANDOM_ATTR_PREFIX_MAX_ITERATIONS = 30;
Expand Down Expand Up @@ -1462,6 +1465,52 @@ public static void setElementTextContent(Element element, String value) {
element.setTextContent(value);
}

public static void setElementTextContentWithCDATAPrefix(Element element, String value) {
CDATASection cdataElement = element.getOwnerDocument().createCDATASection(value);
element.appendChild(cdataElement);
}

public static boolean containsHTML(String code) {
if (StringUtils.isBlank(code)) {
return false;
}

List<String> lines = code.lines().filter(line -> !line.trim().startsWith("#") && !line.isBlank()).toList();

if (lines.isEmpty()) {
return false;
}

if (lines.size() == 1) {
String line = lines.get(0).trim();
String tag = "</";
if (!line.startsWith("<") || !line.contains(">")) {
return false;
} else {
tag += line.substring(1, line.indexOf(">") + 1);
}

if (!line.endsWith(tag)) {
return false;
}
} else {
String tag = "</";
String firstLine = lines.get(0).trim();
if (!firstLine.startsWith("<") || !firstLine.contains(">")) {
return false;
} else {
tag += firstLine.substring(1, firstLine.indexOf(">") + 1);
}

String lastLine = lines.get(lines.size() - 1).trim();
if (!lastLine.contains(tag)) {
return false;
}
}

return true;
}

public static void checkValidXmlChars(String stringValue) {
if (stringValue == null) {
return;
Expand Down

0 comments on commit edfd224

Please sign in to comment.