diff --git a/src/java/net/brutex/xservices/types/AttributeType.java b/src/java/net/brutex/xservices/types/AttributeType.java new file mode 100644 index 0000000..c5ac273 --- /dev/null +++ b/src/java/net/brutex/xservices/types/AttributeType.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013 Brian Rosenberger (Brutex Network) + * + * 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 net.brutex.xservices.types; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +import net.brutex.xservices.util.BrutexNamespaces; + +/** + * @author Brian Rosenberger, bru(at)brutex.de + * + */ +@XmlType(namespace=BrutexNamespaces.WS_XSERVICES, name=AttributeType.XML_NAME) +public class AttributeType { + public final static String XML_NAME = "AttributeType"; + @XmlElement(required=true, nillable=false) + public String name; + @XmlElement(nillable=true) + public String value; +} diff --git a/src/java/net/brutex/xservices/ws/XmlService.java b/src/java/net/brutex/xservices/ws/XmlService.java index 8b47103..d198cfc 100644 --- a/src/java/net/brutex/xservices/ws/XmlService.java +++ b/src/java/net/brutex/xservices/ws/XmlService.java @@ -21,7 +21,9 @@ import javax.jws.WebParam; import javax.jws.WebService; import javax.xml.bind.annotation.XmlElement; +import net.brutex.xservices.types.AttributeType; import net.brutex.xservices.types.NamespaceListType; +import net.brutex.xservices.types.StringSplitType; import net.brutex.xservices.types.ant.FileResource; import org.apache.cxf.annotations.WSDLDocumentation; @@ -43,6 +45,7 @@ public abstract interface XmlService @WSDLDocumentation("Insert an XML fragment into an XML document given as string.") public abstract String insertNodes( @WebParam(name="sourcexml") String source, + @WebParam(name="encoding") String encoding, @WebParam(name="namespaceList") NamespaceListType paramNamespaceListType, @WebParam(name="xpath") @XmlElement(required=true) String paramString1, @WebParam(name="xmldata") String paramString2) @@ -60,7 +63,8 @@ public abstract interface XmlService @WebMethod(operationName="replaceNodes") @WSDLDocumentation("Replaces matched XML nodes with an XML document given as string.") public abstract String replaceNodes( - @WebParam(name="sourcexml") String source, + @WebParam(name="sourcexml") String source, + @WebParam(name="encoding") String encoding, @WebParam(name="namespaceList") NamespaceListType paramNamespaceListType, @WebParam(name="xpath") @XmlElement(required=true) String paramString1, @WebParam(name="xmldata") String paramString2) @@ -79,5 +83,24 @@ public abstract interface XmlService @WSDLDocumentation("Wraps a String into a CDATA element") public abstract String wrapInCDATA(@WebParam(name="data") @XmlElement(required=true) String data) throws XServicesFault; + + @WebMethod(operationName="selectXPath") + @WSDLDocumentation("Select from xml document given as string using an XPath expression.") + public abstract StringSplitType selectXPath( + @WebParam(name="sourcexml") @XmlElement(required=true) String source, + @WebParam(name="encoding") String encoding, + @WebParam(name="namespaceList") NamespaceListType paramNamespaceListType, + @WebParam(name="xpath") @XmlElement(required=true) String paramString1) + throws XServicesFault; + + @WebMethod(operationName="setAttribute") + @WSDLDocumentation("Set an attribute.") + public abstract String setAttribute( + @WebParam(name="sourcexml") @XmlElement(required=true) String source, + @WebParam(name="encoding") String encoding, + @WebParam(name="namespaceList") NamespaceListType paramNamespaceListType, + @WebParam(name="xpath") @XmlElement(required=true) String paramString1, + @WebParam(name="attribute") @XmlElement(nillable=false, required=true) AttributeType attr) + throws XServicesFault; } diff --git a/src/java/net/brutex/xservices/ws/impl/XmlServiceImpl.java b/src/java/net/brutex/xservices/ws/impl/XmlServiceImpl.java index cc0b992..9e369b9 100644 --- a/src/java/net/brutex/xservices/ws/impl/XmlServiceImpl.java +++ b/src/java/net/brutex/xservices/ws/impl/XmlServiceImpl.java @@ -21,26 +21,37 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import javax.jws.WebService; +import javax.xml.namespace.QName; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; + +import net.brutex.xservices.types.AttributeType; import net.brutex.xservices.types.NamespaceListType; import net.brutex.xservices.types.NamespaceType; +import net.brutex.xservices.types.StringSplitType; import net.brutex.xservices.types.ant.FileResource; import net.brutex.xservices.ws.XServicesFault; import net.brutex.xservices.ws.XmlService; import org.apache.axiom.om.OMAbstractFactory; +import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMCloneOptions; +import org.apache.axiom.om.OMComment; import org.apache.axiom.om.OMContainer; import org.apache.axiom.om.OMDocument; import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNode; +import org.apache.axiom.om.OMProcessingInstruction; import org.apache.axiom.om.OMText; import org.apache.axiom.om.OMXMLBuilderFactory; import org.apache.axiom.om.xpath.AXIOMXPath; @@ -72,13 +83,7 @@ public class XmlServiceImpl implements XmlService { } // Initialize XPath context - SimpleNamespaceContext context = new SimpleNamespaceContext(); - for (NamespaceType ns : nsList.getNamespaces()) { - context.addNamespace(ns.getPrefix(), ns.getUri().toString()); - this.logger.debug(Messages.getString("XmlService.0") - + ns.getPrefix() + "=\"" + ns.getUri().toString() - + "\"'"); - } + SimpleNamespaceContext context = createContext(nsList); axp.setNamespaceContext(context); axp.addNamespaces(fragdoc.getOMDocumentElement()); @@ -103,87 +108,51 @@ public class XmlServiceImpl implements XmlService { } } - public String replaceNodesFromFile(FileResource res, NamespaceListType nsList, String xpath, String replace) throws XServicesFault { + public String replaceNodesFromFile(FileResource res, NamespaceListType nsList, String xpath, String xmlFragment) throws XServicesFault { try { - AXIOMXPath axp = new AXIOMXPath(xpath); - - InputStream is = res.getAntResource(null).getInputStream(); - - XMLStreamReader reader = OMXMLBuilderFactory.createOMBuilder(is) - .getDocument().getXMLStreamReader(false); - StringWriter sw = new StringWriter(); - OMAbstractFactory.getOMFactory(); - - while (reader.hasNext()) { - if (reader.getEventType() == 1) { - OMElement element = OMXMLBuilderFactory - .createStAXOMBuilder(reader).getDocumentElement(); - element.build(); - - SimpleNamespaceContext context = new SimpleNamespaceContext(); - for (NamespaceType ns : nsList.getNamespaces()) { - context.addNamespace(ns.getPrefix(), ns.getUri() - .toString()); - this.logger.debug(Messages.getString( - "XmlService.adding_namespace", - new Object[] { ns.getPrefix(), - ns.getUri().toString() })); - } - axp.setNamespaceContext(context); - axp.addNamespaces(element); - - OMDocument xfrag = OMXMLBuilderFactory.createOMBuilder( - new StringReader("" + replace + "")) + AXIOMXPath axp = new AXIOMXPath(xpath); + InputStream is = res.getAntResource(null).getInputStream(); + OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument(); + OMDocument fragdoc = null; + if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) { + fragdoc = OMXMLBuilderFactory.createOMBuilder( + new StringReader("" + xmlFragment + "")) .getDocument(); - xfrag.build(); - - List list = axp.selectNodes(element); - for (Iterator localIterator2 = list.iterator(); localIterator2 - .hasNext();) { - Object o = localIterator2.next(); - if (!(o instanceof OMNode)) - throw new XServicesFault( - "You must match a node to be replaced, but you matched something differen (attribute, etc."); - OMNode node = (OMNode) o; - - Iterator children = xfrag.getOMDocumentElement() - .getChildren(); - while (children.hasNext()) { - OMNode container = (OMNode) children.next(); - node.insertSiblingAfter((OMNode) container - .clone(new OMCloneOptions())); - } - node.detach(); - - // node.insertSiblingAfter(AXIOMUtil.stringToOM(replace)); - - } - XMLOutputFactory xof = XMLOutputFactory.newInstance(); - XMLStreamWriter writer = xof.createXMLStreamWriter(sw); - element.serialize(writer); - sw.flush(); } else { - reader.next(); + throw new XServicesFault("No xmldata to insert."); } + + // Initialize XPath context + SimpleNamespaceContext context = createContext(nsList); + axp.setNamespaceContext(context); + axp.addNamespaces(fragdoc.getOMDocumentElement()); + + OMDocument document = replaceNodes(sourcedoc, axp, fragdoc); + + StringWriter sw = new StringWriter(); + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + XMLStreamWriter writer = xof.createXMLStreamWriter(sw); + document.serialize(writer); + + this.logger.trace(sw.getBuffer().toString()); + return sw.getBuffer().toString(); + } catch (JaxenException e) { + e.printStackTrace(); + throw new XServicesFault(e); + } catch (XMLStreamException e) { + e.printStackTrace(); + throw new XServicesFault(e); + } catch (IOException e) { + e.printStackTrace(); + throw new XServicesFault(e); } - this.logger.trace(sw.getBuffer().toString()); - return sw.getBuffer().toString(); - } catch (JaxenException e) { - e.printStackTrace(); - throw new XServicesFault(e); - } catch (IOException e) { - e.printStackTrace(); - throw new XServicesFault(e); - } catch (XMLStreamException e) { - e.printStackTrace(); - throw new XServicesFault(e); - } } - public String replaceNodes(String source, NamespaceListType nsList, String xpath, String xmlFragment) throws XServicesFault { + public String replaceNodes(String source, String encoding, NamespaceListType nsList, String xpath, String xmlFragment) throws XServicesFault { + encoding = validateEncoding(encoding); try { AXIOMXPath axp = new AXIOMXPath(xpath); - InputStream is = new ByteArrayInputStream(source.getBytes()); + InputStream is = new ByteArrayInputStream(source.getBytes(encoding)); OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is) .getDocument(); OMDocument fragdoc = null; @@ -196,13 +165,7 @@ public class XmlServiceImpl implements XmlService { } // Initialize XPath context - SimpleNamespaceContext context = new SimpleNamespaceContext(); - for (NamespaceType ns : nsList.getNamespaces()) { - context.addNamespace(ns.getPrefix(), ns.getUri().toString()); - this.logger.debug(Messages.getString("XmlService.0") - + ns.getPrefix() + "=\"" + ns.getUri().toString() - + "\"'"); - } + SimpleNamespaceContext context = createContext(nsList); axp.setNamespaceContext(context); axp.addNamespaces(fragdoc.getOMDocumentElement()); @@ -221,13 +184,16 @@ public class XmlServiceImpl implements XmlService { } catch (XMLStreamException e) { e.printStackTrace(); throw new XServicesFault(e); + } catch (UnsupportedEncodingException e) { + throw new XServicesFault(e); } } - public String insertNodes(String source, NamespaceListType nsList, String xpath, String xmlFragment) throws XServicesFault { + public String insertNodes(String source, String encoding, NamespaceListType nsList, String xpath, String xmlFragment) throws XServicesFault { + encoding = validateEncoding(encoding); try { AXIOMXPath axp = new AXIOMXPath(xpath); - InputStream is = new ByteArrayInputStream(source.getBytes()); + InputStream is = new ByteArrayInputStream(source.getBytes(encoding)); OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is) .getDocument(); OMDocument fragdoc = null; @@ -240,13 +206,7 @@ public class XmlServiceImpl implements XmlService { } // Initialize XPath context - SimpleNamespaceContext context = new SimpleNamespaceContext(); - for (NamespaceType ns : nsList.getNamespaces()) { - context.addNamespace(ns.getPrefix(), ns.getUri().toString()); - this.logger.debug(Messages.getString("XmlService.0") - + ns.getPrefix() + "=\"" + ns.getUri().toString() - + "\"'"); - } + SimpleNamespaceContext context = createContext(nsList); axp.setNamespaceContext(context); axp.addNamespaces(fragdoc.getOMDocumentElement()); @@ -265,6 +225,8 @@ public class XmlServiceImpl implements XmlService { } catch (XMLStreamException e) { e.printStackTrace(); throw new XServicesFault(e); + } catch (UnsupportedEncodingException e) { + throw new XServicesFault(e); } } @@ -280,6 +242,115 @@ public class XmlServiceImpl implements XmlService { result = ""; return result; } + + public StringSplitType selectXPath(String source, String encoding, NamespaceListType nsList, String xpath) throws XServicesFault { + encoding = validateEncoding(encoding); + try { + StringSplitType rarray = new StringSplitType(); + AXIOMXPath axp = new AXIOMXPath(xpath); + InputStream is = new ByteArrayInputStream(source.getBytes(encoding)); + OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument(); + + // Initialize XPath context + SimpleNamespaceContext context = createContext(nsList); + + axp.setNamespaceContext(context); + List results = axp.selectNodes(sourcedoc); + for(Object o : results) { + String text = null; + + if(o instanceof OMNode) { + switch (((OMNode)o).getType()) { + case OMNode.TEXT_NODE: + text = ((OMText)o).getText(); + break; + case OMNode.COMMENT_NODE: + text = ((OMComment)o).getValue(); + break; + case OMNode.PI_NODE: + text = ((OMProcessingInstruction)o).getValue(); + break; + default: + StringWriter sw = new StringWriter(); + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + XMLStreamWriter writer = xof.createXMLStreamWriter(sw); + ((OMNode)o).serialize(writer); + writer.flush(); + text = sw.toString(); + } + } else if(o instanceof OMAttribute) { + text = ((OMAttribute)o).getAttributeValue(); + } else { + text = String.valueOf(o); + } + rarray.addStringMatch(text); + } + + + return rarray; + } catch (JaxenException e) { + e.printStackTrace(); + throw new XServicesFault(e); + } catch (XMLStreamException e) { + // TODO Auto-generated catch block + throw new XServicesFault(e.getMessage()); + } catch (UnsupportedEncodingException e) { + throw new XServicesFault(e); + } + } + + public String setAttribute(String source, String encoding, NamespaceListType nsList, String xpath, AttributeType attr) throws XServicesFault { + encoding = validateEncoding(encoding); + try { + StringSplitType rarray = new StringSplitType(); + AXIOMXPath axp = new AXIOMXPath(xpath); + InputStream is = new ByteArrayInputStream(source.getBytes(encoding)); + OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument(); + OMFactory fac = OMAbstractFactory.getOMFactory(); + + // Initialize XPath context + SimpleNamespaceContext context = createContext(nsList); + + axp.setNamespaceContext(context); + List results = axp.selectNodes(sourcedoc); + for(Object o : results) { + String text = null; + + if(o instanceof OMNode) { + switch (((OMNode)o).getType()) { + case OMNode.ELEMENT_NODE: + OMElement node = ((OMElement)o); + if(attr.value == null) { + node.removeAttribute( node.getAttribute(new QName(attr.name))); + } else { + node.addAttribute(attr.name, attr.value, node.getNamespace()); + } + break; + default: + throw new XServicesFault("XPath expression did not match an element node."); + } + } else { + throw new XServicesFault("XPath expression did not match a node."); + } + } + + StringWriter sw = new StringWriter(); + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + XMLStreamWriter writer = xof.createXMLStreamWriter(sw); + sourcedoc.serialize(writer); + writer.flush(); + return sw.toString(); + } catch (JaxenException e) { + e.printStackTrace(); + throw new XServicesFault(e); + } catch (XMLStreamException e) { + // TODO Auto-generated catch block + throw new XServicesFault(e.getMessage()); + } catch (UnsupportedEncodingException e) { + throw new XServicesFault(e); + } + } + private OMDocument insertNodes(OMDocument xmldocument, AXIOMXPath axp,OMDocument xmlfragment) throws XServicesFault { List olist = null; try { @@ -405,4 +476,31 @@ public class XmlServiceImpl implements XmlService { xmldocument.build(); return xmldocument; } + + private SimpleNamespaceContext createContext(NamespaceListType nsList) { + // Initialize XPath context + SimpleNamespaceContext context = new SimpleNamespaceContext(); + if(nsList != null) { + for (NamespaceType ns : nsList.getNamespaces()) { + context.addNamespace(ns.getPrefix(), ns.getUri().toString()); + this.logger.debug(Messages.getString("XmlService.0") + + ns.getPrefix() + "=\"" + ns.getUri().toString() + + "\"'"); + } + } else { + logger.debug("No namespaces defined."); + } + return context; + } + + private String validateEncoding(String encoding) throws XServicesFault { + if(encoding == null || encoding.equals("")) { encoding=Charset.defaultCharset().displayName(); } + try { + Charset.isSupported(encoding); + } catch (IllegalCharsetNameException e) { + throw new XServicesFault("Endcoding '"+encoding+"' is not supported by this JRE."); + } + logger.debug("Setting source xml string encoding to '"+encoding+"'"); + return encoding; + } }