NIFI-1421 Update SplitXML to support namespace declarations

This commit is contained in:
Richard Miskin 2016-01-21 20:35:44 +00:00
parent 92062f9beb
commit 68a9375f3e
3 changed files with 65 additions and 0 deletions

View File

@ -21,8 +21,10 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
@ -193,6 +195,7 @@ public class SplitXml extends AbstractProcessor {
private final int splitDepth;
private final StringBuilder sb = new StringBuilder(XML_PROLOGUE);
private int depth = 0;
private HashMap<String, String> prefixMap = new HashMap<>();
public XmlSplitterSaxParser(XmlElementNotifier notifier, int splitDepth) {
this.notifier = notifier;
@ -261,6 +264,7 @@ public class SplitXml extends AbstractProcessor {
@Override
public void endPrefixMapping(String prefix) throws SAXException {
prefixMap.remove(prefixToNamespace(prefix));
}
@Override
@ -293,19 +297,49 @@ public class SplitXml extends AbstractProcessor {
sb.append("<");
sb.append(qName);
final Set<String> attributeNames = new HashSet<>();
int attCount = atts.getLength();
for (int i = 0; i < attCount; i++) {
String attName = atts.getQName(i);
attributeNames.add(attName);
String attValue = StringEscapeUtils.escapeXml10(atts.getValue(i));
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(">");
}
}
@Override
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;
}
}

View File

@ -92,6 +92,25 @@ public class TestSplitXml {
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 {
for (MockFlowFile out : flowfiles) {
final byte[] outData = out.toByteArray();
@ -99,4 +118,5 @@ public class TestSplitXml {
saxParser.parse(new InputSource(new StringReader(outXml)), new DefaultHandler());
}
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<bundle xmlns:foo="http://namespace/1">
<node>
<foo:subNode1 attribute="d&amp;b">
<value>Hello &amp; Goodbye</value>
</foo:subNode1>
<foo:subNode2 xmlns:goo="http://namespace/2">
<goo:value>World</goo:value>
</foo:subNode2>
</node>
</bundle>