2017-07-07 80 views
2

我需要使用SAX解析器进行xml转换,因为我需要从xml中删除名称空间。由于我们正在处理巨大的XML,我需要使用SAX解析器。如何使用SAX解析器删除xml namesapce

样品输入的xml:

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" 
xmlns:ns2="http://www.google.com/generation/type"> 
    <ns2:meta> 
     <gender xmlns="" xmlns:ns5="http://www.google.com/generation">M</gender> 
     <dateOfBirth xmlns="" xmlns:ns5="http://www.google.com/generation">1976-07-19</dateOfBirth> 
     <ns2:languageRef>ENG</ns2:languageRef> 
    </ns2:meta> 
    <root> 

用SAX解析器的帮助下,我需要的下方输出。

 <root> 
      <meta> 
       <gender>M</gender> 
       <dateOfBirth>1976-07-19</dateOfBirth> 
       <languageRef>ENG</languageRef> 
      </ns2:meta> 
     <root> 

预先感谢..

其中我试图代码,

我试图与XMLFlterImpl,

XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) { 

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

    if (qName.contains(":")) { 
     String[] data = data = qName.split(":"); 


     super.startElement(uri, localName, data[1], atts); 
    } else { 
     super.startElement(uri, localName, qName, atts); 
    } 
    } 

这消除元素名称前缀(命名空间),但不确定如何删除命名空间属性

+0

您需要使用SAX还是可以使用StAX? – nandsito

+0

仅使用sax解析器 – pradeep

+0

是否允许您使用StAX编写XML输出,因为SAX不写XML? – nandsito

回答

1

编辑:

好,与来自@MichaelKay评论的方向,这是我更新的答案。

从标签中删除命名空间:

正如他的回答提出的,startElement应该代替uri""。怎么样结束标记?: 在你的问题我不明白你为什么要ns2结尾meta标记,特别是当你想删除它的开始标记。 我假设你希望它也被删除以结束标签。所以同样endElement也应该有""代替uri

过滤XMLNS属性:

您可以创建一个新的AttributesImpl。然后通过属性的列表,如果QName开始检查与xmlns,如果不将它添加到AttributesImpl和使用它作为startElement

super.startElement("", localName, data[1], aImpl);

另外请注意,按照@MartinHonnen,是的属性'uri也应该是“”,并且qName应该与元素一样没有前缀。但是如果你想保留这些属性的名字(我不认为你想要),你可以保持原来的atts.getQName(i)

还建立命名空间功能以假像:

xf.setFeature("http://xml.org/sax/features/namespaces", false);

代码:

try { 

    InputSource file = new InputSource("filterns.xml"); 

    XMLFilterImpl xf = new XMLFilterImpl(
      XMLReaderFactory.createXMLReader()) { 
     @Override 
     public void startElement(String uri, String localName, 
      String qName, Attributes atts) throws SAXException { 

       AttributesImpl aImpl = new AttributesImpl(); 

       int l = atts.getLength(); 
       for (int i = 0; i < l; i++) { 

        if (atts.getQName(i) != null 
          && atts.getQName(i).startsWith("xmlns")) { 
         continue; 
        } else { 
         String aQName = atts.getQName(i); 
         String[] s = aQName.split(":"); 
         if (s.length > 1) { 
          aQName = s[1]; 
         } 

         aImpl.addAttribute("", 
           atts.getLocalName(i), aQName, 
           atts.getType(i), atts.getValue(i)); 
        } 

       } 

       String[] s = qName.split(":"); 
       if (s.length > 1) { 
        super.startElement("", localName, s[1], aImpl); 
       } else { 
        super.startElement("", localName, qName, aImpl); 
       } 

     } 

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

       String[] s = qName.split(":"); 
       if (s.length > 1) { 
       super.endElement("", localName, s[1]); 
       } else { 
        super.endElement("", localName, qName); 
       } 

     } 

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

    }; 

    xf.setFeature("http://xml.org/sax/features/namespaces", false); 
    SAXSource src = new SAXSource(xf, file); 

    StringWriter stringWriter = new StringWriter(); 
    TransformerFactory transformerFactory = TransformerFactory 
      .newInstance(); 
    Transformer transformer = transformerFactory.newTransformer(); 
    transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes"); 
    transformer.transform(src, new StreamResult(stringWriter)); 

    String xml = stringWriter.toString(); 
    System.out.println(xml); 

} catch (Exception e) { 
    e.printStackTrace(); 
} 
+1

这是一个可怕的方法 - 你没有试图逃避输出中的特殊字符!一般来说,手动序列化几乎与手动解析一样严重。在某些方面,情况更糟,因为其他人将不得不处理您创建的无效输出。 –

+0

@MichaelKay好的我明白了,我很好奇,如果我必须这样做,我该如何逃避特殊字符。此外,我只是追加解析器中的任何内容吗?我错过了什么? – SomeDude

+0

要做到这一点并不困难,尽管很多人似乎无法正确地做到这一点,但最好的方法是使用现有的序列化库。例如,一种常用的方法是对StreamResult进行身份转换。 –

0

通常尝试t o删除命名空间以执行“转换”是缺乏对如何处理XML的理解的标志,但一般来说,如果您使用SAX并希望更改已处理的XML,则可以实现过滤器https://docs.oracle.com/javase/8/docs/api/org/xml/sax/XMLFilter.html,以https://docs.oracle.com/javase/8/docs/api/org/xml/sax/helpers/XMLFilterImpl.html作为基础语言开头,并且覆盖您期望的方法并且想要去除命名空间。

+0

我试过XMLFilterImpl,添加了我试过的代码 – pradeep

+0

你能否帮我删除名称空间属性 – pradeep

+0

我对SAX API并不熟悉,看起来应该使用https://docs.oracle.com/javase/ 8/docs/api/org/xml/sax/ext/Attributes2Impl.html#Attributes2Impl--从您的处理程序接收到的属性中构建新属性,当然,您必须确保新属性没有原始属性有。你将不得不尝试一下,但我相信你可以解决它。 –

1

在此代码:

super.startElement(uri, localName, data[1], atts); 

你逝去的原始命名空间URI不变为输出。你需要摆脱它,使用:

super.startElement("", localName, data[1], atts); 
+0

嗨,这不起作用 – pradeep

0

这是VTD-XML可以做的一个例子。如果有任何问题,请告诉我。

import com.ximpleware.*; 
import java.io.*; 
public class removeNS { 

    public static void main(String[] args) throws VTDException, IOException{ 
     // TODO Auto-generated method stub 
     VTDGen vg = new VTDGen(); 
     if (!vg.parseFile("d:\\xml\\ns.xml", true)) 
      return; 
     VTDNav vn = vg.getNav(); 
     XMLModifier xm = new XMLModifier(vn); 
     for (int i=0;i<vn.getTokenCount();i++){ 

      int t = vn.getTokenType(i); 
      switch(t){ 

       case VTDGen.TOKEN_STARTING_TAG: 
        stripElementPrefix(i,vn,xm); 
        break; 
       case VTDGen.TOKEN_ATTR_NAME: 
        stripAttrPrefix(i,vn,xm); 
        break; 
       case VTDGen.TOKEN_ATTR_NS: 
        xm.removeAttribute(i); 
       default: 
      } 
     } 
     xm.output("d:\\xml\\nsOut.xml"); 
    } 

    public static void stripAttrPrefix(int i, VTDNav vn, XMLModifier xm) throws VTDException{ 
     //get the offset and length of localname part of starting tag 
     int os1 = vn.getTokenOffset(i); 
     int len = vn.getTokenLength(i); 
     if ((len>>16)!=0){ 
      int temp1 = (0xffff & len) - (len>>16)-1; 
      int temp2 = os1 + (temp1); 
      xm.removeContent(temp1, temp2); 
     } 

     //int offset= 
    } 

    public static void stripElementPrefix(int i, VTDNav vn, XMLModifier xm) throws VTDException, UnsupportedEncodingException{ 
     //int os1 = vn.getTokenOffset(i) 
     int os1 = vn.getTokenOffset(i); 
     int len = vn.getTokenLength(i); 
     if ((len>>16)!=0){ 
      int temp1 = (0xffff & len) - (len>>16)-1; 
      int temp2 = os1 + (len>>16)+1; 
      String s = vn.toRawString(temp2, temp1); 
      System.out.println(s); 
      vn.recoverNode(i); 
      xm.updateElementName(s); 
     } 
    } 

}