001package com.streamconverter.command.impl.xml;
002
003import com.streamconverter.StreamProcessingException;
004import com.streamconverter.command.AbstractStreamCommand;
005import com.streamconverter.command.rule.IRule;
006import com.streamconverter.path.TreePath;
007import com.streamconverter.security.SecureXmlConfiguration;
008import java.io.IOException;
009import java.io.InputStream;
010import java.io.OutputStream;
011import java.util.ArrayList;
012import java.util.List;
013import java.util.Objects;
014import javax.xml.stream.XMLEventFactory;
015import javax.xml.stream.XMLEventReader;
016import javax.xml.stream.XMLEventWriter;
017import javax.xml.stream.XMLInputFactory;
018import javax.xml.stream.XMLOutputFactory;
019import javax.xml.stream.XMLStreamException;
020import javax.xml.stream.events.XMLEvent;
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024/**
025 * XML変換コマンドクラス
026 *
027 * <p>このクラスは、XML形式のデータを変換するためのコマンドを実装します。 ストリームを使用して、XMLデータを読み込み、変換後のデータを出力します。
028 * 変換対象のXPathである箇所を特定したあとに、変換処理を実行することを想定しています。
029 */
030public class ConvertCommand extends AbstractStreamCommand {
031
032  private static final Logger logger = LoggerFactory.getLogger(ConvertCommand.class);
033  private IRule rule;
034  private TreePath treePath;
035
036  /**
037   * デフォルトコンストラクタ
038   *
039   * @param rule 変換ルール
040   * @param treePath 変換対象のTreePath
041   */
042  public ConvertCommand(IRule rule, TreePath treePath) {
043    super();
044    Objects.requireNonNull(rule, "rule must not be null");
045    Objects.requireNonNull(treePath, "treePath must not be null");
046    this.rule = rule;
047    this.treePath = treePath;
048  }
049
050  /**
051   * XML変換コマンドの実行
052   *
053   * @param inputStream 入力ストリーム
054   * @param outputStream 出力ストリーム
055   * @throws IOException 入出力エラーが発生した場合
056   * @throws StreamProcessingException XML処理エラーが発生した場合
057   */
058  @Override
059  protected void executeInternal(InputStream inputStream, OutputStream outputStream)
060      throws IOException {
061    // StaXを使用したXML変換処理を実装する
062    // ここでは、IRuleを使用して変換処理を行うことを想定しています。
063    // 例: XMLを読み込み、IRuleを適用して変換し、出力ストリームに書き込む処理を実装する
064    XMLInputFactory xmlInputFactory = SecureXmlConfiguration.createSecureXMLInputFactory();
065    XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
066
067    try {
068      XMLEventReader xmlEventReader = xmlInputFactory.createXMLEventReader(inputStream);
069      XMLEventWriter xmlEventWriter = xmlOutputFactory.createXMLEventWriter(outputStream);
070
071      try {
072        List<String> currentDirectory = new ArrayList<>();
073        while (xmlEventReader.hasNext()) {
074          XMLEvent event = xmlEventReader.nextEvent();
075          int eventType = event.getEventType();
076          switch (eventType) {
077            // 現在地点を保持するための処理
078            case XMLEvent.START_ELEMENT:
079              // 現在のXpathを保持する
080              currentDirectory.add(event.asStartElement().getName().getLocalPart());
081              break;
082            case XMLEvent.END_ELEMENT:
083              // 現在のXpathを保持する
084              currentDirectory.remove(currentDirectory.size() - 1);
085              break;
086            // 変換対象の箇所なら変換処理を実行する
087            case XMLEvent.CHARACTERS:
088              if (this.treePath.matches(currentDirectory)) {
089                String transformedData = rule.apply(event.asCharacters().getData());
090                event = XMLEventFactory.newDefaultFactory().createCharacters(transformedData);
091              }
092              break;
093            default:
094              // Handle other events if necessary
095              break;
096          }
097          // Write the event to the output stream
098          xmlEventWriter.add(event);
099        }
100      } finally {
101        // リソースのクリーンアップ
102        try {
103          if (xmlEventWriter != null) {
104            xmlEventWriter.close();
105          }
106        } catch (XMLStreamException e) {
107          logger.warn("XMLEventWriterのクローズ中にエラーが発生しました: {}", e.getMessage(), e);
108        }
109        try {
110          if (xmlEventReader != null) {
111            xmlEventReader.close();
112          }
113        } catch (XMLStreamException e) {
114          logger.warn("XMLEventReaderのクローズ中にエラーが発生しました: {}", e.getMessage(), e);
115        }
116      }
117    } catch (XMLStreamException e) {
118      logger.error("XML処理中にエラーが発生しました: {}", e.getMessage(), e);
119      throw new StreamProcessingException("XML変換処理に失敗しました", e);
120    }
121  }
122}