All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.prowidesoftware.swift.io.parser.XMLParser Maven / Gradle / Ivy

There is a newer version: SRU2024-10.2.3
Show newest version
/*
 * Copyright 2006-2023 Prowide
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.prowidesoftware.swift.io.parser;

import com.prowidesoftware.swift.io.writer.FINWriterVisitor;
import com.prowidesoftware.swift.model.*;
import com.prowidesoftware.swift.model.field.Field;
import com.prowidesoftware.swift.utils.SafeXmlUtils;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * This is the main parser for WIFE's XML internal representation.
* The supported XML format is consider internal because it is an ad-hoc * defined XML structure for Swift messages, so it's not the SWIFT XML * Standard for FIN Messages.
*
*

* This implementation should be used by calling some of the the conversion * services. * * @author sebastian * @see com.prowidesoftware.swift.io.IConversionService * @since 5.0 */ public class XMLParser { private static final transient java.util.logging.Logger log = java.util.logging.Logger.getLogger(XMLParser.class.getName()); private static final String UNPARSEDTEXTS = "unparsedtexts"; /** * Given a String containing a message in its WIFE internal XML * representation, returns a SwiftMessage object. * If there is any error during conversion this method returns null * * @param xml the string containing the XML to parse * @return the XML parsed into a SwiftMessage object * @see com.prowidesoftware.swift.io.IConversionService#getMessageFromXML(java.lang.String) */ public SwiftMessage parse(final String xml) { Validate.isTrue(xml != null); try { final DocumentBuilder db = SafeXmlUtils.documentBuilder(); final Document doc = db.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); return createMessage(doc); } catch (final Exception e) { log.log(Level.WARNING, "Error parsing XML", e); return null; } } /** * Helper method for XML representation parsing.
* * @param doc Document object containing a message in XML format * @return SwiftMessage object populated with the given XML message data */ private SwiftMessage createMessage(final Document doc) { final NodeList messageNL = doc.getElementsByTagName("message"); if (messageNL.getLength() == 1) { final Node message = messageNL.item(0); final SwiftMessage m = new SwiftMessage(false); final NodeList blocksNL = message.getChildNodes(); if (log.isLoggable(Level.FINE)) { log.fine("blocks in message: " + blocksNL.getLength()); } for (int i = 0; i < blocksNL.getLength(); i++) { final Node blockNode = blocksNL.item(i); if (log.isLoggable(Level.FINE)) { log.fine("evaluating node " + blockNode.getNodeName()); } if (blockNode.getNodeType() == Node.ELEMENT_NODE) { final String blockName = blockNode.getNodeName(); if ("block1".equalsIgnoreCase(blockName)) { m.setBlock1(getBlock1FromNode(blockNode)); } else if ("block2".equalsIgnoreCase(blockName)) { m.setBlock2(getBlock2FromNode(blockNode)); } else if (UNPARSEDTEXTS.equalsIgnoreCase(blockName)) { // unparsed texts at level m.setUnparsedTexts(getUnparsedTextsFromNode(blockNode)); } else { // blocks 3, 4, 5 or user blocks m.addBlock(getTagListBlockFromNode(blockNode)); } } } // end block list iteration return m; } else { throw new IllegalArgumentException(" tag not found"); } } /** * Helper method for XML representation parsing.
* Given the <block1> node in the XML tree, returns the SwiftBlock1 object. * * @param blockNode Node object of the <block1> tag in the XML message * @return SwiftBlock1 object populated with the given portion of the XML message */ private SwiftBlock1 getBlock1FromNode(final Node blockNode) { final NodeList fields = blockNode.getChildNodes(); if (log.isLoggable(Level.FINE)) { log.fine(fields.getLength() + " children in "); } final SwiftBlock1 b1 = new SwiftBlock1(); for (int i = 0; i < fields.getLength(); i++) { final Node n = fields.item(i); if ("APPLICATIONID".equalsIgnoreCase(n.getNodeName())) { b1.setApplicationId(getText(n)); } else if ("SERVICEID".equalsIgnoreCase(n.getNodeName())) { b1.setServiceId(getText(n)); } else if ("LOGICALTERMINAL".equalsIgnoreCase(n.getNodeName())) { b1.setLogicalTerminal(getText(n)); } else if ("SESSIONNUMBER".equalsIgnoreCase(n.getNodeName())) { b1.setSessionNumber(getText(n)); } else if ("SEQUENCENUMBER".equalsIgnoreCase(n.getNodeName())) { b1.setSequenceNumber(getText(n)); } else if (UNPARSEDTEXTS.equalsIgnoreCase(n.getNodeName())) { b1.setUnparsedTexts(getUnparsedTextsFromNode(n)); } } return b1; } private String getText(final Node n) { String text = null; final Node c = n.getFirstChild(); if (c != null) { if (c.getNodeType() == Node.TEXT_NODE) { text = c.getNodeValue(); } else { log.warning("Node is not TEXT_NODE: " + c); } } return text; } /** * Helper method for XML representation parsing.
* Given the <block2> node in the XML tree, returns the SwiftBlock1 object. * The method checks for the "type" attribute in the <block2> tag and * returns a SwiftBlock2Input or SwiftBlock2Output. * * @param blockNode Node object of the <block2> tag in the XML message * @return SwiftBlock2 object populated with the given portion of the XML message * @see #getBlock2InputFromNode(Node) * @see #getBlock2OutputFromNode(Node) */ private SwiftBlock2 getBlock2FromNode(final Node blockNode) { final String type = getNodeAttribute(blockNode, "type"); if (type == null) { log.severe("atrribute 'type' was expected but not found at xml tag"); return null; } else if ("input".equals(type)) { return getBlock2InputFromNode(blockNode); } else if ("output".equals(type)) { return getBlock2OutputFromNode(blockNode); } else { log.severe( "expected 'input' or 'output' value for 'type' atribute at xml tag, and found: " + type); return null; } } /** * Helper method for XML representation parsing.
* Given the <block2 type="input"> node in the XML tree, returns the * SwiftBlock2Input object. * * @param blockNode Node object of the <block2> tag in the XML message * @return SwiftBlock2Input object populated with the given portion of the XML message */ private SwiftBlock2Input getBlock2InputFromNode(final Node blockNode) { final NodeList fields = blockNode.getChildNodes(); if (log.isLoggable(Level.FINE)) { log.fine(fields.getLength() + " childrens in "); } final SwiftBlock2Input b2 = new SwiftBlock2Input(); for (int i = 0; i < fields.getLength(); i++) { final Node n = fields.item(i); if ("MESSAGETYPE".equalsIgnoreCase(n.getNodeName())) { b2.setMessageType(getText(n)); } else if ("RECEIVERADDRESS".equalsIgnoreCase(n.getNodeName())) { b2.setReceiverAddress(getText(n)); } else if ("MESSAGEPRIORITY".equalsIgnoreCase(n.getNodeName())) { b2.setMessagePriority(getText(n)); } else if ("DELIVERYMONITORING".equalsIgnoreCase(n.getNodeName())) { b2.setDeliveryMonitoring(getText(n)); } else if ("OBSOLESCENCEPERIOD".equalsIgnoreCase(n.getNodeName())) { b2.setObsolescencePeriod(getText(n)); } else if (UNPARSEDTEXTS.equalsIgnoreCase(n.getNodeName())) { b2.setUnparsedTexts(getUnparsedTextsFromNode(n)); } } return b2; } /** * Helper method for XML representation parsing.
* Given the <block2 type="output" node in the XML tree, returns the * SwiftBlock2Output object. * * @param blockNode Node object of the <block2> tag in the XML message * @return SwiftBlock2Output object populated with the given portion of the XML message */ private SwiftBlock2Output getBlock2OutputFromNode(final Node blockNode) { final NodeList fields = blockNode.getChildNodes(); if (log.isLoggable(Level.FINE)) { log.fine(fields.getLength() + " childrens in "); } final SwiftBlock2Output b2 = new SwiftBlock2Output(); for (int i = 0; i < fields.getLength(); i++) { final Node n = fields.item(i); if ("MESSAGETYPE".equalsIgnoreCase(n.getNodeName())) { b2.setMessageType(getText(n)); } else if ("SENDERINPUTTIME".equalsIgnoreCase(n.getNodeName())) { b2.setSenderInputTime(getText(n)); } else if ("MIRDATE".equalsIgnoreCase(n.getNodeName())) { b2.setMIRDate(getText(n)); } else if ("MIRLOGICALTERMINAL".equalsIgnoreCase(n.getNodeName())) { b2.setMIRLogicalTerminal(getText(n)); } else if ("MIRSESSIONNUMBER".equalsIgnoreCase(n.getNodeName())) { b2.setMIRSessionNumber(getText(n)); } else if ("MIRSEQUENCENUMBER".equalsIgnoreCase(n.getNodeName())) { b2.setMIRSequenceNumber(getText(n)); } else if ("RECEIVEROUTPUTDATE".equalsIgnoreCase(n.getNodeName())) { b2.setReceiverOutputDate(getText(n)); } else if ("RECEIVEROUTPUTTIME".equalsIgnoreCase(n.getNodeName())) { b2.setReceiverOutputTime(getText(n)); } else if ("MESSAGEPRIORITY".equalsIgnoreCase(n.getNodeName())) { b2.setMessagePriority(getText(n)); } else if (UNPARSEDTEXTS.equalsIgnoreCase(n.getNodeName())) { b2.setUnparsedTexts(getUnparsedTextsFromNode(n)); } } return b2; } /** * Helper method for XML representation parsing.
* Given the <block3>, <block4>, <block5> or <block> (user block) node in * the XML tree, returns the corresponding SwiftTagListBlock object * populated with the given portion of the XML message. * * @param blockNode Node object of the <block3>, <block4>, <block5> or <block> tag in the XML message * @return SwiftTagListBlock object populated with the given portion of the XML message */ private SwiftTagListBlock getTagListBlockFromNode(final Node blockNode) { final String blockName = blockNode.getNodeName(); SwiftTagListBlock b; if ("block3".equalsIgnoreCase(blockName)) { b = new SwiftBlock3(); } else if ("block4".equalsIgnoreCase(blockName)) { b = new SwiftBlock4(); } else if ("block5".equalsIgnoreCase(blockName)) { b = new SwiftBlock5(); } else if ("block".equalsIgnoreCase(blockName)) { final String name = getNodeAttribute(blockNode, "name"); if (name != null) { b = new SwiftBlockUser(name); } else { b = new SwiftBlockUser(); } } else { return null; } final NodeList fields = blockNode.getChildNodes(); if (log.isLoggable(Level.FINE)) { log.fine(fields.getLength() + " children in tag list " + blockName); } for (int j = 0; j < fields.getLength(); j++) { final Node t = fields.item(j); if ("tag".equalsIgnoreCase(t.getNodeName())) { final Tag tag = getTag(t); b.append(tag); } else if ("field".equalsIgnoreCase(t.getNodeName())) { final Field field = getField(t); b.append(field); } else if (UNPARSEDTEXTS.equalsIgnoreCase(t.getNodeName())) { b.setUnparsedTexts(getUnparsedTextsFromNode(t)); } } return b; } /** * Helper method for XML representation parsing.
* Parses the given <tag> Node and returns a Tag object containing data from * the expected <name> and <value> tags. If name or value are not found as * children of the given node, the Tag object is returned with empty values. * * @param t the XML node to parse for name-value pair * @return a Tag object containing the name and value of the given XML node. */ private Tag getTag(final Node t) { final Tag tag = new Tag(); final NodeList children = t.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { final Node n = children.item(i); if ("name".equalsIgnoreCase(n.getNodeName())) { tag.setName(getText(n)); } if ("value".equalsIgnoreCase(n.getNodeName())) { String text = getText(n); // normalize line feeds (DOM parser removes carriage return characters from original XML file) text = StringUtils.replace(text, "\n", FINWriterVisitor.SWIFT_EOL); tag.setValue(text); } else if (UNPARSEDTEXTS.equalsIgnoreCase(n.getNodeName())) { tag.setUnparsedTexts(getUnparsedTextsFromNode(n)); } } return tag; } /** * Helper method for XML representation parsing.
* Parses the given >field< Node and returns a Field object containing data from * the expected <name> and <component> inner elements. * If <name> element is not set it will return null. Otherwise it will return a Field * instance filled with content from <component> elements. * * @param t the XML node to parse for name-value pair * @return a Field object or null if "name" element is not present */ private Field getField(final Node t) { final NodeList children = t.getChildNodes(); String name = null; for (int i = 0; i < children.getLength(); i++) { final Node n = children.item(i); if ("name".equalsIgnoreCase(n.getNodeName())) { name = getText(n); break; } } if (name != null) { Field field = Field.getField(name, null); for (int i = 0; i < children.getLength(); i++) { final Node n = children.item(i); if ("component".equalsIgnoreCase(n.getNodeName())) { final String number = getNodeAttribute(n, "number"); if (StringUtils.isNumeric(number)) { String text = getText(n); // normalize line feeds (DOM parser removes carriage return characters from original XML file) text = StringUtils.replace(text, "\n", FINWriterVisitor.SWIFT_EOL); try { field.setComponent(Integer.parseInt(number), text); } catch (NumberFormatException e) { log.warning( "error setting component " + number + " for field " + name + ": " + e.getMessage()); return null; } } } } return field; } return null; } /** * Helper method for XML representation parsing.
* Given the <unparsedtexts> node in the XML tree, returns an * UnparsedTextList object populated with the contents of the child * tags of <unparsedtexts>. * * @param blockNode Node object of the <unparsedtexts> tag in the XML message * @return UnparsedTextList object populated with the given <text> tags content of the <unparsedtexts> */ private UnparsedTextList getUnparsedTextsFromNode(final Node blockNode) { final UnparsedTextList unparsedTexts = new UnparsedTextList(); final NodeList texts = blockNode.getChildNodes(); if (log.isLoggable(Level.FINE)) { log.fine(texts.getLength() + " children in "); } for (int j = 0; j < texts.getLength(); j++) { final Node t = texts.item(j); if ("text".equalsIgnoreCase(t.getNodeName())) { unparsedTexts.addText(getText(t)); } } return unparsedTexts; } /** * Helper method for XML representation parsing.
* Gets the value of an expected attribute in a Node. * * @param n Node to analyze to find the attribute * @param attributeName the attribute name expected in the analyzed Node n * @return the value of the attribute expected, or null if the attribute was not found */ private String getNodeAttribute(final Node n, final String attributeName) { final Node attr = n.getAttributes().getNamedItem(attributeName); if (attr == null || !attr.getNodeName().equals(attributeName)) { return null; } else { return attr.getNodeValue(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy