【问题标题】:Using SAX parser, need all the xml elements(under a particular element) as a string使用 SAX 解析器,需要所有 xml 元素(在特定元素下)作为字符串
【发布时间】:2017-06-14 11:22:10
【问题描述】:

我需要使用 sax 解析器将所有 xml 元素(在特定元素下)作为来自下面 xml 的字符串。

示例 xml:

<root>
  <meta>
    <elememtA>xx</elememtA>
  </meta>
 <payload>
    <parent>
        <child1>a</child1>
   </parent>
   <parent>
        <child1>b</child1>
   </parent>
  </payload>
</root>

Sax 解析器实现:

public class UserHandler extends DefaultHandler {  
    @Override
    public void startElement(String uri, 
    String localName, String qName, Attributes attributes)
    throws SAXException {
    if (qName.equalsIgnoreCase("payload")) {
    //need all elements inside payload as string
}

例如,

我需要休闲输出:

<parent><child1>a</child1></parent><parent><child2>b</child2></parent>

【问题讨论】:

  • 嗨,你的意思是:ab
  • 嗨,我没听懂你
  • 刚刚编辑了帖子,第二个参数是b
  • 字符串还是字节数组?
  • 字符串输入

标签: java xml saxparser


【解决方案1】:

这里是工作代码。 你可以在输出的底线看到你的结果。享受吧。

输出

2017-06-14 09:43:49 DEBUG SaxTest:94 - start document
2017-06-14 09:43:49 DEBUG SaxTest:107 - START -  - parent
2017-06-14 09:43:49 DEBUG SaxTest:107 - START -  - child1
2017-06-14 09:43:49 DEBUG SaxTest:33 - STRING : a
2017-06-14 09:43:49 DEBUG SaxTest:52 - END -  - child1
2017-06-14 09:43:49 DEBUG SaxTest:52 - END -  - parent
2017-06-14 09:43:49 DEBUG SaxTest:107 - START -  - parent
2017-06-14 09:43:49 DEBUG SaxTest:107 - START -  - child1
2017-06-14 09:43:49 DEBUG SaxTest:33 - STRING : b
2017-06-14 09:43:49 DEBUG SaxTest:52 - END -  - child1
2017-06-14 09:43:49 DEBUG SaxTest:52 - END -  - parent
2017-06-14 09:43:49 DEBUG SaxTest:41 - end document
2017-06-14 09:43:49 INFO  SaxTest:148 - RESULT 
<parent><child1>a</child1></parent><parent><child1>b</child1></parent>

Junit 中的代码 - 带有工作测试

package com.rizze.beans.labs.sof;

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class SaxTest {

    public static Logger logger = LoggerFactory.getLogger(SaxTest.class);


    public class SaxProcess implements ContentHandler {

        private boolean start= false;
        private static final String START_ITEM = "payload";
        private String result = "";

        @Override
        public void characters(char[] ch, int begin, int length) throws SAXException {
            if(start == true){
                logger.debug("STRING : "+new String(ch).substring(begin,begin+length));

                result+=new String(new String(ch).substring(begin,begin+length));
            }
        }

        @Override
        public void endDocument() throws SAXException {
                        logger.debug("end document");
        }

        @Override
        public void endElement(String uri, String localName, String name) throws SAXException {

            if(name!=null && name.compareToIgnoreCase(START_ITEM)==0){
                start = false;
            }
            else{
                if(start == true){
                    logger.debug("END - "+ localName + " - " + name);
                    result+="</"+name+">";
                }
            }


        }

        @Override
        public void endPrefixMapping(String prefix) throws SAXException {



        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {

        }

        @Override
        public void processingInstruction(String target, String data) throws SAXException {


        }

        @Override
        public void setDocumentLocator(Locator locator) {

        }

        @Override
        public void skippedEntity(String name) throws SAXException {


        }

        @Override
        public void startDocument() throws SAXException {
            start=false;
            result = "";

            logger.debug("start document");
        }

        @Override
        public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {

            if(name!=null && name.compareToIgnoreCase(START_ITEM)==0){
                start = true;
            }
            else{

                if(start == true){
                    //if already started ... go on
                    logger.debug("START - "+ localName + " - " + name);
                    result+="<"+name+">";
                }
            }


        }

        @Override
        public void startPrefixMapping(String prefix, String uri) throws SAXException {


        }

        /**
         * return resulting string
         * @return
         */
        public String getResult(){
            return result;
        }

    }





    @Test
    public void test() {


        String xml = "<root><meta><elememtA>xx</elememtA></meta><payload><parent><child1>a</child1></parent><parent><child1>b</child1></parent></payload></root>";
        InputSource in = new InputSource(new StringReader(xml));


            try {
                XMLReader  reader= SAXParserFactory.newInstance().newSAXParser().getXMLReader();
                SaxProcess p=new SaxProcess();
                reader.setContentHandler(p);
                reader.parse(in);
                logger.info("RESULT \n"+p.getResult());
            } catch (ParserConfigurationException | SAXException | IOException e) {
                e.printStackTrace();
            }

    }

}

【讨论】:

  • @svasa => 问题是如何在 SAX 中使用 ContentHandler。此代码响应问题,也适用于单个文件。如果去掉日志记录/导入....,您将减少 50% 的代码大小。
【解决方案2】:

看来您需要 xml 格式的输出,即您需要 xml 形式的 parent 节点。 SAXParser 或 XPath 引擎使用节点和节点名称。您必须编写特殊代码以将所需的输出作为 xml 返回,这可能非常麻烦且难以维护。

轻松获得所需输出 xml 的一种方法是使用 XSLT。

考虑使用 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
    <xsl:copy-of select="//payload/parent"/>
</xsl:template>
</xsl:stylesheet>

把它放在一个名为parentxslt.xml的文件中,并将你的输入xml放在parent.xml中,然后你可以使用下面的java代码:

try
{
    File stylesheet = new File( "parentxslt.xml" );
    Transformer transformer = TransformerFactory.newInstance().newTransformer( new StreamSource(stylesheet) );
    StreamSource xmlSource = new StreamSource( new File( "parent.xml" ) );
    StringWriter sw = new StringWriter();
    transformer.transform( xmlSource, new StreamResult( sw ) );

    System.out.println( sw.toString().replaceAll("\\\r\\n\\s*", "") );

}
catch ( Exception ex )
{
   ex.printStackTrace();
}

【讨论】:

  • 不要仅仅因为想要转换它就创建 DOM。最好为转换器提供 StreamSource 或 SAXSource。
  • @MichaelKay 感谢您的评论!我更新了我的代码以使用StreamSource
  • 另外,为什么不把它减少到&lt;xsl:copy-of select="//payload/parent"/&gt;
  • @MichaelKay 再次感谢。也修改了 xsl。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
  • 1970-01-01
  • 2014-02-27
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
相关资源
最近更新 更多