2017-02-17 73 views
8

我有一个相当复杂的JAXB树对象。 对于每一片叶子节点,我需要滤波其实际值JAXB编组:筛选叶元素的值

例如

<Book> 
    <Title>Yogasana Vijnana: the Science of Yoga</Title> 
    <Author>Dhirendra Brahmachari</Author> 
    <Date>1966</Date> 
</Book> 

叶节点这里将TitleauthorDate
想象一下,我需要一个整理文档此JAXB模型的每一片叶子节点删除的第一个字符:

<Book> 
    <Title>ogasana Vijnana: the Science of Yoga</Title> 
    <Author>hirendra Brahmachari</Author> 
    <Date>966</Date> 
</Book> 


什么是最好的方法?
我看到两个起点,但是,我目前卡住了。

1.不要在JAXB模型
的变化是有,我可以用它来得到任何JAXB对象(某种Visitor模式或东西)的片式元件的一些遍历mechnism?

2.钩到编组
也许我们可以挂接到编组,例如使用一个XMLStreamWriter ..

有没有这种问题的优雅解决方案?

回答

9

基于XMLStreamWriter类型的装饰另一种方法这将简单地跳过文本内容的第一个字符,但是您无法将其限制为仅限叶节点,它会将相同的逻辑应用于不仅仅是叶节点的所有文本内容,如果你的编组不会产生混乱的内容(如你的例子)。事实上,如果您没有混合内容(文本内容和节点混合在一起),则只有叶节点可以具有文本内容。

装饰可能是这样的:

public class RemoveFirstCharacter implements XMLStreamWriter { 

    private final XMLStreamWriter delegate; 

    public RemoveFirstCharacter(final XMLStreamWriter delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public void writeStartElement(final String localName) throws XMLStreamException { 
     delegate.writeStartElement(localName); 
    } 

    @Override 
    public void writeStartElement(final String namespaceURI, final String localName) 
     throws XMLStreamException { 
     delegate.writeStartElement(namespaceURI, localName); 
    } 

    ... 

    @Override 
    public void writeCharacters(final String text) throws XMLStreamException { 
     // Skip the first character 
     delegate.writeCharacters(text.substring(1)); 
    } 

    @Override 
    public void writeCharacters(final char[] text, final int start, final int len) 
     throws XMLStreamException { 
     if (start == 0) { 
      // Skip the first character 
      delegate.writeCharacters(text, 1, len - 1); 
     } else { 
      delegate.writeCharacters(text, start, len); 
     } 
    } 
} 

那么你的代码将是:

// Create the marshaller for the class Book 
JAXBContext jaxbContext = JAXBContext.newInstance(Book.class); 
Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

// Create the main XMLStreamWriter 
XMLOutputFactory output = XMLOutputFactory.newInstance(); 
XMLStreamWriter writer = output.createXMLStreamWriter(System.out); 

// Apply the custom XMLStreamWriter that will remove the first character 
// of each text content 
jaxbMarshaller.marshal(book, new RemoveFirstCharacter(writer)); 
6

你可以后处理产生的XML删除使用XSLT下一个样式表的每个叶子节点的文本内容的第一个字符:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="*"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 
    <!-- For each text content of leaf nodes (nodes without child nodes) --> 
    <xsl:template match="*[not(*)]/text()"> 
     <!-- Skip the first character --> 
     <xsl:value-of select="substring(., 2)"/> 
    </xsl:template> 
</xsl:stylesheet> 

根据你造成XML的大小您可以在应用样式表之前将结果保存到内存中,或者先将结果XML存储到临时文件中。

下面是你的代码可以假设产生XML可以放入内存:

// Create the marshaller for the class Book 
JAXBContext jaxbContext = JAXBContext.newInstance(Book.class); 
Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

// Make the output being pretty printed 
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

// Marshall the book instance and keep the result into a ByteArrayOutputStream 
ByteArrayOutputStream out = new ByteArrayOutputStream(); 
jaxbMarshaller.marshal(book, out); 

TransformerFactory factory = TransformerFactory.newInstance(); 
// Define the stylesheet to apply 
Transformer transformer = factory.newTransformer(new StreamSource(xsltFile)); 
// Define the input XML content 
Source text = new StreamSource(new ByteArrayInputStream(out.toByteArray())); 
// Apply the stylesheet and store the content into outputFile 
transformer.transform(text, new StreamResult(outputFile)); 

输出:

<?xml version="1.0" encoding="UTF-8"?> 
<Book> 
    <Title>ogasana Vijnana: the Science of Yoga</Title> 
    <Author>hirendra Brahmachari</Author> 
    <Date>966</Date> 
</Book>