【问题标题】:JAXB marshalling: Filter values of leaf elementsJAXB 编组:过滤叶元素的值
【发布时间】:2017-02-17 15:02:47
【问题描述】:

我有一个相当复杂的 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 对象(某种访问者模式或其他东西)的叶元素?

2。钩入编组
也许我们可以加入编组,例如使用XMLStreamWriter..

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

【问题讨论】:

    标签: java xml jaxb marshalling


    【解决方案1】:

    另一种基于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));
    

    【讨论】:

      【解决方案2】:

      您可以后处理生成的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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-23
        • 2014-01-05
        相关资源
        最近更新 更多