tags:

views:

127

answers:

2

I want to transform XML like this:

<account>Wally World</account>
<city>Anywhere</city>
<state>CA</state>

Into this by wrapping each element with equals and single quote i.e. =''

<account>='Wally World'</account>
<city>='Anywhere'</city>
<state>='CA'</state>

Need to transform all the element text in large XML files using Java, maybe with XSLT?

+1  A: 

If you want to just use SAX to make this type of simple change, here is the code:

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.XMLReaderFactory;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class XMLPipeline {

    public static void main(String[] args) throws Exception {
        String inputFile = "a.xml";
        PrintStream outputStream = System.out;
        new XMLPipeline().process(inputFile, outputStream);
    }

    //default JDK
    public void process(String inputFile, OutputStream outputStream) throws
            SAXException, ParserConfigurationException, IOException, TransformerException {
        StreamResult xwriter = new StreamResult(outputStream);
        XMLReader xreader = XMLReaderFactory.createXMLReader();
        XMLAnalyzer analyzer = new XMLAnalyzer(xreader);
        TransformerFactory stf = SAXTransformerFactory.newInstance();
        SAXSource ss = new SAXSource(analyzer, new InputSource(inputFile));
        stf.newTransformer().transform(ss, xwriter);
    }

    public static class XMLAnalyzer extends XMLFilterImpl {

        private Set<String> tags = new HashSet<String>(Arrays.asList("account", "city", "state"));
        boolean bufferText = false;
        StringBuilder buffer;

        public XMLAnalyzer(XMLReader xmlReader) {
            super(xmlReader);
        }


        @Override
        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
            super.startElement(uri, localName, qName, atts);
            if (tags.contains(localName)) {
                buffer = new StringBuilder("='");
                bufferText = true;
            }
        }

        @Override
        public void characters(char[] chars, int i, int i1) throws SAXException {
            if (bufferText) {
                buffer.append(chars, i, i1);
            } else {
                super.characters(chars, i, i1);
            }
        }

        @Override
        public void endElement(String s, String s1, String s2) throws SAXException {
            if (bufferText) {
                buffer.append('\'');
                super.characters(buffer.toString().toCharArray(), 0, buffer.length());
                bufferText = false;
            }
            super.endElement(s, s1, s2);
        }

    }
}
Chandra Patni
+2  A: 

In XSLT it could be something like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

    <xsl:template match="account|city|state">
        <xsl:element name="{local-name(.)}">
            <xsl:text disable-output-escaping="yes">=&apos;</xsl:text>
            <xsl:value-of select="text()"/>
            <xsl:text disable-output-escaping="yes">&apos;</xsl:text>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Note that it will only change account, city and state elements, and leave all other elements intact. So a document like this:

<items>
    <item>
        <account>Wally World</account>
        <city>Anywhere</city>
        <state>CA</state>
    </item>
</items>

... would change into this:

<items>
    <item>
        <account>='Wally World'</account>
        <city>='Anywhere'</city>
        <state>='CA'</state>
    </item>
</items>
Wilfred Springer