2010年2月14日日曜日

[java][dom]ネストした要素をフラットに再配置する

例えばfontタグの中にfontタグを入れないように一個ずつ閉じましょうみたいなことです。
次の実装の例は親子関係をフラットに再配置します。ただし、矯正できるのは親子関係(二代)までです。


---
/**
 * ネストした要素をフラットに再配置します。
 * 
 * 変換前
 * <phrase>We <phrase>are </phrase>the <phrase>world.</phrase></phrase>;
 * 変換後
 * <phrase>We </phrase><phrase>are </phrase><phrase>the </phrase><phrase>world.</phrase>
 * @param target
 */
public static void flattenNestedElement(final Element target){
  if(target == null) throw new IllegalArgumentException();
  
  String targetName = target.getNodeName();
  Element parent = (Element)target.getParentNode();
  for(int i=0;i<target.getChildNodes().getLength();){
    Node child = target.getChildNodes().item(i);
    if(child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(targetName)){
      parent.insertBefore(child, target);
    }else{
      Node copy = target.cloneNode(false);
      parent.insertBefore(copy, target);
      copy.appendChild(child);
    }
  }
  parent.removeChild(target);
}
---

テストケースです。
---
@Test
public void testFlattenNestedElement_DocBook4_Phrase() throws Exception{
  StringBuilder sb = new StringBuilder();
  sb.append("<section><para>");
  sb.append("<phrase revisionflag=\"changed\">基本 XML 値を");
  sb.append("<phrase revision=\"01\"><emphasis role=\"bold\">定数</emphasis>として</phrase>");
  sb.append("格納する");
  sb.append("<phrase revision=\"02\">ユーティリティー</phrase>");
  sb.append("クラスです。</phrase>");
  sb.append("</para></section>");
  String xml = sb.toString();
  
  sb.setLength(0);
  sb.append("<section><para>");
  sb.append("<phrase revisionflag=\"changed\">基本 XML 値を</phrase>");
  sb.append("<phrase revision=\"01\"><emphasis role=\"bold\">定数</emphasis>として</phrase>");
  sb.append("<phrase revisionflag=\"changed\">格納する</phrase>");
  sb.append("<phrase revision=\"02\">ユーティリティー</phrase>");
  sb.append("<phrase revisionflag=\"changed\">クラスです。</phrase>");
  sb.append("</para></section>");
  String expected = sb.toString();
  
  Document doc = DomUtils.stringToDocument(xml);
  NodeList nodeList = DomUtils.findNodesByXPath(doc, "/section/para/phrase");
  Element target = (Element)nodeList.item(0);
  DomUtils.flattenNestedElement(target);
  String actual = DomUtils.nodeToString(doc);
  actual = XMLUtils.removeXMLDeclaration(actual);
  assertEquals(expected, actual);
}
---

ではまた。

0 件のコメント:

コメントを投稿