5

org.w3c.dom.Node必要な XML 関連コードの量を最小限に抑えながら、ツリー内の特定のオブジェクト (または のインスタンスなどorg.w3c.dom.Element) を作成したクラスのインスタンスにダウンキャストできるように、XML ドキュメントを Java の DOM ツリーに解析したいと考えています。(再)実装する。(非常に単純な) 例として、次のような XML 要素があるとします。

<Vector size="5">
  1.0 -1.0 3.0 -2.73e2
</Vector>

パーサーをカスタマイズして、以下をインスタンス化したいと思います。

public class Vector extends /* some parser class */ {
  private double[] elements;

  /* constructors; etc.*/

  public double dotProduct(Vector v) {
    /* implementation */
  }
}

Vectorたとえば、パーサーによって作成された のインスタンスをjavax.xml.xpathオブジェクトのメソッドに渡して、それらを正しく機能させることができます。これを達成する最も速い方法は何ですか?Java SE だけで可能ですか、それともサードパーティのライブラリ (Xerces など) が必要ですか?

4

3 に答える 3

1

あなたの要件が何であるかはわかりませんが、XML がどのように見えるかを制御できると仮定すると、私が使用するのはXStreamです。すべての DOM 操作を完全にスキップできます。

彼らの 2 分間のチュートリアルから、このユース ケース用に構築されているようには見えないかもしれませんが、実際にはそうです。最初に Java クラスを作成し、希望どおりの XML が生成されることを確認してから、それを使用して既存の XML を XStream オブジェクトとしてプログラムに読み込みます。使っていてとても楽しい図書館です。

于 2013-05-17T00:29:53.430 に答える
0

注: 私はEclipseLink JAXB (MOXy)のリーダーであり、JAXB (JSR-222)エキスパート グループのメンバーです。

JAXBのBinderメカニズムは、探しているものかもしれません。DOM ノードをドメイン オブジェクトにキャストすることはできませんが、ドメイン オブジェクトとそれに対応する DOM ノードの間のリンクは維持されます。

注: 次のコードは、MOXy を JAXB プロバイダーとして使用すると問題なく実行されましたが、たまたま実行している JDK のバージョンに含まれている JAXB の impl を使用すると例外がスローされました。

ジャバモデル

この例では、次のドメイン モデルを使用します。

お客様

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Customer {

    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();

    @XmlElementWrapper
    @XmlElement(name="phoneNumber")
    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

}

電話番号

import javax.xml.bind.annotation.*;

public class PhoneNumber {

    private String type;
    private String number;

    @XmlAttribute
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @XmlValue
    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

}

jaxb.properties

MOXy を JAXB プロバイダーとして指定するにはjaxb.properties、次のエントリを使用して、ドメイン モデルと同じパッケージで呼び出されるファイルを含める必要があります ( http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-asを参照)。 -your.html )

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

XML (input.xml)

<?xml version="1.0" encoding="UTF-8"?>
<customer>
    <phoneNumbers>
        <phoneNumber type="work">555-1111</phoneNumber>
        <phoneNumber type="home">555-2222</phoneNumber>
    </phoneNumbers>
</customer>

デモコード

以下のデモコードでは、次のことを行います。

  1. XPath を使用して子要素を見つけ、次に を使用しBinderて対応するドメイン オブジェクトを見つけます。
  2. ドメイン オブジェクトを更新し、 を使用しBinderて変更を DOM に適用します。
  3. DOM を更新し、 を使用Binderしてドメイン オブジェクトに変更を適用します。

デモ

import javax.xml.bind.Binder;
import javax.xml.bind.JAXBContext;
import javax.xml.parsers.*;
import javax.xml.xpath.*;

import org.w3c.dom.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse("src/forum16599580/input.xml");

        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();

        JAXBContext jc = JAXBContext.newInstance(Customer.class);
        Binder<Node> binder = jc.createBinder();
        binder.unmarshal(document);

        // Use Node to Get Object
        Node phoneNumberElement = (Node) xpath.evaluate("/customer/phoneNumbers/phoneNumber[2]", document, XPathConstants.NODE);
        PhoneNumber phoneNumber = (PhoneNumber) binder.getJAXBNode(phoneNumberElement);

        // Modify Object to Update DOM
        phoneNumber.setNumber("555-2OBJ");
        binder.updateXML(phoneNumber);
        System.out.println(xpath.evaluate("/customer/phoneNumbers/phoneNumber[2]", document, XPathConstants.STRING));

        // Modify DOM to Update Object
        phoneNumberElement.setTextContent("555-2DOM");
        binder.updateJAXB(phoneNumberElement);
        System.out.println(phoneNumber.getNumber());
    }

}

出力

555-2OBJ
555-2DOM
于 2013-05-17T03:06:30.773 に答える
0

私は過去 10 年間、化学、グラフィックス、数学などの XML DOM を構築してきました。私自身の解決策は、要素をサブクラス化できる DOM を使用することでした (私は xom.nu を使用しますが、他にもあります)。 . w3c dom ではサブクラス化 (IIRC) が許可されていないため、デリゲート モデルを構築する必要があります。(私は何年も前にこれを試して拒否しましたが、ソフトウェア ツールとライブラリにより、これらすべてがはるかに簡単になります (たとえば、IDE はデリゲート メソッドを生成します)。

多くのことを行っている場合、特に多くのカスタム メソッドを作成している場合は、独自のシステムを展開することをお勧めします。労力は、XML ではなく、メソッド (dotProduct) にあります。

たとえば、これは 3D point のクラスです

public class CMLPoint3 extends AbstractPoint3 

(これは基本クラス CMLElement を拡張し、nu.xom.Element を拡張します

要素の作成は工場です。これが私の SVGDOM の一部です:

public static SVGElement readAndCreateSVG(Element element) {
    SVGElement newElement = null;
    String tag = element.getLocalName();
    if (tag == null || tag.equals(S_EMPTY)) {
        throw new RuntimeException("no tag");
    } else if (tag.equals(SVGCircle.TAG)) {
        newElement = new SVGCircle();
    } else if (tag.equals(SVGClipPath.TAG)) {
        newElement = new SVGClipPath();
    } else if (tag.equals(SVGDefs.TAG)) {
        newElement = new SVGDefs();
    } else if (tag.equals(SVGDesc.TAG)) {
        newElement = new SVGDesc();
    } else if (tag.equals(SVGEllipse.TAG)) {
        newElement = new SVGEllipse();
    } else if (tag.equals(SVGG.TAG)) {

...
    } else {
            newElement = new SVGG();
            newElement.setClassName(tag);
            System.err.println("unsupported svg element: "+tag);
        }
        if (newElement != null) {
            newElement.copyAttributesFrom(element);
            createSubclassedChildren(element, newElement);
        }
        return newElement;

コピーと再帰のためのツールを見ることができます。

考える必要がある質問は次のとおりです。

  • これは XSD にどのくらい密接にバインドされていますか
  • XSD データ型を使用する必要がありますか
  • 入力時に検証しますか
  • DOM を主要なデータ構造として使用していますか (使用しています)
  • どのくらいの頻度で物事が変化しますか。

FWIW 私はこれを 6 回改訂しましたが、別のバージョンを考えています (メイン エンジンとして Scala を使用)。

于 2013-05-17T08:53:59.623 に答える