mirror of https://github.com/apache/nifi.git
NIFI-1421 Update SplitXML to support namespace declarations
This commit is contained in:
parent
92062f9beb
commit
68a9375f3e
|
@ -21,8 +21,10 @@ import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
@ -193,6 +195,7 @@ public class SplitXml extends AbstractProcessor {
|
||||||
private final int splitDepth;
|
private final int splitDepth;
|
||||||
private final StringBuilder sb = new StringBuilder(XML_PROLOGUE);
|
private final StringBuilder sb = new StringBuilder(XML_PROLOGUE);
|
||||||
private int depth = 0;
|
private int depth = 0;
|
||||||
|
private HashMap<String, String> prefixMap = new HashMap<>();
|
||||||
|
|
||||||
public XmlSplitterSaxParser(XmlElementNotifier notifier, int splitDepth) {
|
public XmlSplitterSaxParser(XmlElementNotifier notifier, int splitDepth) {
|
||||||
this.notifier = notifier;
|
this.notifier = notifier;
|
||||||
|
@ -261,6 +264,7 @@ public class SplitXml extends AbstractProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endPrefixMapping(String prefix) throws SAXException {
|
public void endPrefixMapping(String prefix) throws SAXException {
|
||||||
|
prefixMap.remove(prefixToNamespace(prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,19 +297,49 @@ public class SplitXml extends AbstractProcessor {
|
||||||
sb.append("<");
|
sb.append("<");
|
||||||
sb.append(qName);
|
sb.append(qName);
|
||||||
|
|
||||||
|
final Set<String> attributeNames = new HashSet<>();
|
||||||
int attCount = atts.getLength();
|
int attCount = atts.getLength();
|
||||||
for (int i = 0; i < attCount; i++) {
|
for (int i = 0; i < attCount; i++) {
|
||||||
String attName = atts.getQName(i);
|
String attName = atts.getQName(i);
|
||||||
|
attributeNames.add(attName);
|
||||||
String attValue = StringEscapeUtils.escapeXml10(atts.getValue(i));
|
String attValue = StringEscapeUtils.escapeXml10(atts.getValue(i));
|
||||||
sb.append(" ").append(attName).append("=").append("\"").append(attValue).append("\"");
|
sb.append(" ").append(attName).append("=").append("\"").append(attValue).append("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is the first node we're outputting write out
|
||||||
|
// any additional namespace declarations that are required
|
||||||
|
if (splitDepth == newDepth - 1) {
|
||||||
|
for (Entry<String, String> entry : prefixMap.entrySet()) {
|
||||||
|
// If we've already added this namespace as an attribute then continue
|
||||||
|
if (attributeNames.contains(entry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sb.append(" ");
|
||||||
|
sb.append(entry.getKey());
|
||||||
|
sb.append("=\"");
|
||||||
|
sb.append(entry.getValue());
|
||||||
|
sb.append("\" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sb.append(">");
|
sb.append(">");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startPrefixMapping(String prefix, String uri) throws SAXException {
|
public void startPrefixMapping(String prefix, String uri) throws SAXException {
|
||||||
|
final String ns = prefixToNamespace(prefix);
|
||||||
|
prefixMap.put(ns, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String prefixToNamespace(String prefix) {
|
||||||
|
final String ns;
|
||||||
|
if (prefix.length() == 0) {
|
||||||
|
ns = "xmlns";
|
||||||
|
} else {
|
||||||
|
ns="xmlns:"+prefix;
|
||||||
|
}
|
||||||
|
return ns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,25 @@ public class TestSplitXml {
|
||||||
parseFlowFiles(runner.getFlowFilesForRelationship(SplitXml.REL_SPLIT));
|
parseFlowFiles(runner.getFlowFilesForRelationship(SplitXml.REL_SPLIT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNamespaceDeclarations() throws Exception {
|
||||||
|
// Configure a namespace aware parser to ensure namespace
|
||||||
|
// declarations are handled correctly.
|
||||||
|
factory = SAXParserFactory.newInstance();
|
||||||
|
factory.setNamespaceAware(true);
|
||||||
|
saxParser = factory.newSAXParser( );
|
||||||
|
|
||||||
|
final TestRunner runner = TestRunners.newTestRunner(new SplitXml());
|
||||||
|
runner.setProperty(SplitXml.SPLIT_DEPTH, "3");
|
||||||
|
runner.enqueue(Paths.get("src/test/resources/TestXml/namespace.xml"));
|
||||||
|
runner.run();
|
||||||
|
runner.assertTransferCount(SplitXml.REL_ORIGINAL, 1);
|
||||||
|
runner.assertTransferCount(SplitXml.REL_SPLIT, 2);
|
||||||
|
|
||||||
|
parseFlowFiles(runner.getFlowFilesForRelationship(SplitXml.REL_ORIGINAL));
|
||||||
|
parseFlowFiles(runner.getFlowFilesForRelationship(SplitXml.REL_SPLIT));
|
||||||
|
}
|
||||||
|
|
||||||
public void parseFlowFiles(List<MockFlowFile> flowfiles) throws Exception, SAXException {
|
public void parseFlowFiles(List<MockFlowFile> flowfiles) throws Exception, SAXException {
|
||||||
for (MockFlowFile out : flowfiles) {
|
for (MockFlowFile out : flowfiles) {
|
||||||
final byte[] outData = out.toByteArray();
|
final byte[] outData = out.toByteArray();
|
||||||
|
@ -99,4 +118,5 @@ public class TestSplitXml {
|
||||||
saxParser.parse(new InputSource(new StringReader(outXml)), new DefaultHandler());
|
saxParser.parse(new InputSource(new StringReader(outXml)), new DefaultHandler());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bundle xmlns:foo="http://namespace/1">
|
||||||
|
<node>
|
||||||
|
<foo:subNode1 attribute="d&b">
|
||||||
|
<value>Hello & Goodbye</value>
|
||||||
|
</foo:subNode1>
|
||||||
|
<foo:subNode2 xmlns:goo="http://namespace/2">
|
||||||
|
<goo:value>World</goo:value>
|
||||||
|
</foo:subNode2>
|
||||||
|
</node>
|
||||||
|
</bundle>
|
Loading…
Reference in New Issue