QuickFixJ Message class has method toXML() which converts message into xml string. Is there any way I can create message object from the XML string? I need the reverse of toXML() i.e. I want to create Message from xml.
1 Answer
There's nothing like that built in. There doesn't really need to be, as there normally wouldn't be a use-case for it.
I've written a class which does it. The order of the tags might be different from the input message (but the FIX spec makes no guarantees about tag order, except within groups) because the XML exporter sorts by tag number, and so the original tag order is lost.
It only works on a single message in an XML file, but could easily be adapted to work on multiple messages.
You can use the standard MessageUtils.parse to create a Message from the resultant string.
Let me know if you have any problems.
class XmlMessage
{
private final String xml;
private final String delimiter;
XmlMessage(final String xml, final String delimiter)
{
this.xml = xml;
this.delimiter = delimiter;
}
public String toFixMessage() throws IOException, SAXException, ParserConfigurationException
{
final Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream(xml.getBytes()));
final StringBuilder messageBuilder = new StringBuilder();
build(messageBuilder, doc, "header");
build(messageBuilder, doc, "body");
build(messageBuilder, doc, "trailer");
return messageBuilder.toString();
}
private void build(final StringBuilder messageBuilder, final Document doc, final String section)
{
final NodeList sectionRoot = doc.getElementsByTagName(section);
final NodeList sectionChildren = sectionRoot.item(0).getChildNodes();
build(messageBuilder, sectionChildren);
}
private void build(final StringBuilder messageBuilder, final NodeList nodeList)
{
final Set<String> numInGroupTags = getNumInGroupTags(nodeList);
for (int i = 0; i < nodeList.getLength(); i++)
{
final Node node = nodeList.item(i);
if (node.getNodeName().equals("field") && !numInGroupTags.contains(getTagNumber(node)))
{
messageBuilder.append(getTagNumber(node))
.append('=')
.append(node.getTextContent())
.append(delimiter);
}
else if (node.getNodeName().equals("groups"))
{
final NodeList groupElems = node.getChildNodes();
messageBuilder.append(getTagNumber(node))
.append('=')
.append(getGroupCount(groupElems))
.append(delimiter);
for (int j = 0; j < groupElems.getLength(); j++)
{
build(messageBuilder, groupElems.item(j).getChildNodes());
}
}
}
}
private Set<String> getNumInGroupTags(final NodeList nodeList)
{
final Set<String> numInGroupTags = new HashSet<>();
for (int i = 0; i < nodeList.getLength(); i++)
{
if (nodeList.item(i).getNodeName().equals("groups"))
{
numInGroupTags.add(getTagNumber(nodeList.item(i)));
}
}
return numInGroupTags;
}
private String getTagNumber(final Node node)
{
return node.getAttributes().getNamedItem("tag").getTextContent();
}
private int getGroupCount(final NodeList groupRoot)
{
int count = 0;
for (int j = 0; j < groupRoot.getLength(); j++)
{
if (groupRoot.item(j).getNodeName().equals("group")) count++;
}
return count;
}
}