diff --git a/src/main/java/org/xembly/AttrDirective.java b/src/main/java/org/xembly/AttrDirective.java index db3d51f..0cb4103 100644 --- a/src/main/java/org/xembly/AttrDirective.java +++ b/src/main/java/org/xembly/AttrDirective.java @@ -75,8 +75,13 @@ public Directive.Cursor exec(final Node dom, final Directive.Cursor cursor, final Directive.Stack stack) { final String key = this.name.raw(); final String val = this.value.raw(); + final String[] parts = key.split(" "); for (final Node node : cursor) { - Element.class.cast(node).setAttribute(key, val); + if (parts.length == 2) { + Element.class.cast(node).setAttributeNS(parts[1], parts[0], val); + } else { + Element.class.cast(node).setAttribute(key, val); + } } return cursor; } diff --git a/src/main/java/org/xembly/Directives.java b/src/main/java/org/xembly/Directives.java index 4cae7dd..48374b9 100644 --- a/src/main/java/org/xembly/Directives.java +++ b/src/main/java/org/xembly/Directives.java @@ -332,6 +332,10 @@ public Directives remove() { /** * Set attribute. * + *

If it's necessary to add an attribute with a namespace, append + * the namespace to the name of the attribute, separating them + * with a space.

+ * *

If a value provided contains illegal XML characters, a runtime * exception will be thrown. To avoid this, it is recommended to use * {@link Xembler#escape(String)}. diff --git a/src/test/java/org/xembly/AttrDirectiveTest.java b/src/test/java/org/xembly/AttrDirectiveTest.java index 0bc8036..f28ed89 100644 --- a/src/test/java/org/xembly/AttrDirectiveTest.java +++ b/src/test/java/org/xembly/AttrDirectiveTest.java @@ -30,10 +30,12 @@ package org.xembly; import com.jcabi.matchers.XhtmlMatchers; +import com.jcabi.xml.XMLDocument; import java.util.Collections; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.lang3.StringUtils; import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -100,4 +102,19 @@ void addsCaseSensitiveAttributesDirectly() throws Exception { XhtmlMatchers.hasXPath("/f[@Price='\u20ac50']") ); } + + @Test + void addAttributeWithNamespace() { + MatcherAssert.assertThat( + new XMLDocument( + new Xembler( + new Directives().add("boom").attr( + "noNamespaceSchemaLocation http://www.w3.org/2001/XMLSchema-instance", + "foo.xsd" + ) + ).domQuietly() + ).nodes("/boom/@xsi:noNamespaceSchemaLocation"), + Matchers.not(Matchers.emptyIterable()) + ); + } }