2009-08-22 23 views
5

Làm thế nào tôi có thể, với một DOM w3c (thực thi mặc định của Java, cụ thể) thay đổi không gian tên của mỗi phần tử/thuộc tính/nút trong DOM đó? Hiệu quả, tốt nhất. DOM dường như không có phương thức setNamespaceURI trên nó, điều này là bất tiện.Làm cách nào để thay đổi không gian tên trên mỗi nút trong DOM?

Tôi đã thử phương pháp tiếp cận XSL, nhưng chúng đã không hoạt động trong máy biến áp JAXP (mặc dù chúng hoạt động tốt ở Saxon9B mà tôi không thể sử dụng vì nhiều lý do khác).

Về cơ bản, tôi cần một giải pháp java lõi thuần túy sẽ cho phép tôi lấy một tài liệu và thay đổi không gian tên của nó.

+0

XSL có lẽ là giải pháp đơn giản nhất, và nên làm việc trong JAXP. Bạn đã thử làm gì và nó đã thất bại như thế nào? – skaffman

Trả lời

3

Dựa trên ý kiến ​​cực kỳ thiên vị của tôi những gì bạn muốn sẽ là một nỗi đau lớn trong ass. Tôi có thể nhìn thấy địa ngục typecasting và rất nhiều đệ quy cho các vòng lặp cần thiết để làm điều này một cách đáng tin cậy! Ahh, thực hiện mặc định của Java, làm thế nào tôi ghét NPE của bạn: tại internals, logic đảo ngược, các bước bổ sung cần thiết cho hoạt động đơn giản! Vì vậy, có, đề nghị của tôi sẽ được đệ quy cho các vòng với typecasting cho mỗi loại nút duy nhất có thể, dựa trên kinh nghiệm rất cá nhân của tôi thực hiện mặc định của Java sucks rằng nặng.

+0

Tôi nghĩ rằng một số giải pháp khác ở đây là thanh lịch hơn, nhưng đây là những gì tôi đã làm :) –

+0

Trong khi hơi buồn cười, điều này thực sự không nên là câu trả lời được chấp nhận ... –

9

Điều này không hiệu quả trên DOM không gian tên. Bạn sẽ phải sử dụng phương pháp Lõi DOM Cấp 3 Document.renameNode (javadoc) trên mọi Phần tử con cháu có không gian tên bạn muốn thay đổi. (Thông thường, bạn không cần thay đổi nhiều nút Attr, vì không gian tên của nút Attr không có tiền tố luôn là null, thay vì không gian tên của phần tử.)

Nếu tất cả những gì bạn muốn làm là thay thế một vùng tên cho một cách khác, có thể nhanh hơn để sử dụng DOM không gian tên không biết và chỉ cần thay đổi thuộc tính xmlns được đề cập. Bạn sẽ có thể nhận được DOM không gian tên không xác định bằng cách đặt tham số DOMConfiguration ‘không gian tên’ thành false, nhưng tôi đã không thử tính năng này trong Java và đó là loại imps ít điều DOM sẽ bị sai.

2

Nếu ý định chỉ thay đổi không gian tên, thì chỉ cần sử dụng một số trình chỉnh sửa luồng để thay đổi ánh xạ NS thành URL.

Một Namspace ít nhiều liên kết giữa tiền tố không gian tên và URI. Để nhanh chóng thay đổi namespace, chỉ cần thay đổi bản đồ:

Trước: xmlns: myNS = "-namespace-uri của tôi"

Sau: xmlns: myNS = "my-mới-namespace-uri"

Bản đồ thay đổi cơ bản là đủ, nếu ý định chỉ đơn giản là thay đổi không gian tên. Hơn nữa nếu Tài liệu XML có không gian tên mặc định, thì việc thay đổi giá trị URL không gian tên mặc định sẽ thay đổi không gian tên cho toàn bộ tài liệu.

Trước: xmlns = "my-namespace-uri"

Sau: xmlns = "my-mới-namespace-uri"

+0

+1 để thực hiện Java tinh khiết –

+0

Đẹp ý tưởng, nhưng tại thời điểm này mà sẽ yêu cầu tái tuần tự hóa thành luồng byte và phân tích cú pháp lại, điều này KHÔNG được chấp nhận từ quan điểm hiệu suất. Tôi đã có một DOM, mà tôi phải sử dụng. –

0

Không gian tên được thay đổi trên tất cả các yếu tố mà không có một tiền tố namespace định nghĩa bằng cách áp dụng thuộc tính targetnamespace cho phần tử gốc của bạn. Việc làm này cũng sẽ yêu cầu bạn sau đó thay đổi từng phần tử của bạn bằng tiền tố không gian tên. Bạn có thể làm cho tiền tố này thay đổi theo cách thủ công hoặc viết một số logic kịch bản để đi bộ cây DOM của bạn để áp dụng nó chỉ khi cần thiết.

Đây là đọc thêm về các thuộc tính targetnamespace và thuộc tính nonamespaceschema:

http://www.xml.com/pub/a/2000/11/29/schemas/part1.html?page=8 http://www.computerpoweruser.com/editorial/article.asp?article=articles%2Farchive%2Fc0407%2F48c07%2F48c07.asp

2

Làm thế nào tôi có thể, cho một DOM w3c (thực hiện mặc định của Java, cụ thể) thay đổi không gian tên của tất cả các phần tử/thuộc tính/nút trong DOM đó? Hiệu quả, tốt nhất.

Tôi không nghĩ rằng đó là giải pháp hiệu quả cũng mạnh mẽ. Bạn không thể chỉ cần đổi tên một cái gì đó trên phần tử gốc. Hãy xem xét các tài liệu này:

Doc1

<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns="urn:all" xmlns:f="urn:fleet" xmlns:m="urn:mission"> 
    <f:starfleet> 
    <m:bold> 
     <f:ship name="Enterprise" /> 
    </m:bold> 
    </f:starfleet> 
</root> 

Doc2

<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns="urn:all"> 
    <starfleet xmlns="urn:fleet"> 
    <bold xmlns="urn:mission"> 
     <ship xmlns="urn:fleet" name="Enterprise" /> 
    </bold> 
    </starfleet> 
</root> 

Doc3

<?xml version="1.0" encoding="UTF-8"?> 
<r:root xmlns:r="urn:all"> 
    <r:starfleet xmlns:r="urn:fleet"> 
    <r:bold xmlns:r="urn:mission"> 
     <r:ship xmlns:r="urn:fleet" name="Enterprise" /> 
    </r:bold> 
    </r:starfleet> 
</r:root> 

Ba tài liệu tương đương trong một DOM namespace-aware. Bạn có thể chạy cùng một số namespaced XPath queries với bất kỳ người nào trong số họ.

Vì DOM cho phép bạn chỉ định chính xác cách các nút nên được đặt tên, nên không có lệnh gọi một bước nào để thay đổi không gian tên. Bạn cần phải đi bộ DOM, xem xét không chỉ các giá trị tiền tố và URI, mà còn là scope tại bất kỳ thời điểm đã định nào.

XSLT này có thể được sử dụng với một Transformer để thay đổi các yếu tố namespaced như urn:fleet được namespaced như urn:new:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:f="urn:fleet" version="1.0"> 
    <xsl:output method="xml" indent="yes" /> 
    <xsl:template match="*"> 
    <xsl:copy> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="f:*"> 
    <xsl:variable name="var.foo" select="local-name()" /> 
    <xsl:element namespace="urn:new" name="{$var.foo}"> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates /> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

Hãy cẩn thận: tinh chỉnh hơn nữa sẽ được yêu cầu để xử lý các thuộc tính namespaced; Dangling urn:fleet tờ khai có thể được bỏ lại phía sau, đó là lộn xộn, nhưng phần lớn không quan trọng; có lẽ những thứ khác mà tôi chưa từng nghĩ tới.

+0

Đó là những gì tôi đã sử dụng ban đầu, gần như từng từ, nhưng hóa ra là việc sử dụng XML của khách hàng của chúng tôi là ... nguyên thủy. Hay ngu ngốc. Bạn chọn. Các công cụ của họ bị phá vỡ nếu XML không được _laid out_ đúng cách, vì lợi ích của chúa tể. –

0

Bạn có thể sao chép cây DOM của mình sang một cây khác và thực hiện một số chỉnh sửa trong quá trình xử lý. Ví dụ, sử dụng org.apache.xml.utils.DOMBuilder như việc thực hiện các ContentHandler, bạn có thể ghi đè lên các phương pháp theo cách như vậy:

public void startElement(String ns, String localName, String name, Attributes atts) throws SAXException { 
     super.startElement("new_namespace", localName, name, atts); 
    } 

DOMBuilder sẽ xử lý tất cả các công việc bẩn thỉu trong việc sao chép lại cho bạn chỉ thay thế namespace Logic .

0

Nếu bạn là ok với việc sử dụng các lớp Xerces, bạn có thể tạo một DOMParser thay thế URI các thuộc tính và các yếu tố với URI cố định lên của bạn:

import org.apache.xerces.parsers.DOMParser; 

public static class MyDOMParser extends DOMParser { 
    private Map<String, String> fixupMap = ...; 

    @Override 
    protected Attr createAttrNode(QName attrQName) 
    { 
     if (fixupMap.containsKey(attrQName.uri)) 
      attrQName.uri = fixupMap.get(attrQName.uri); 
     return super.createAttrNode(attrQName); 
    } 

    @Override 
    protected Element createElementNode(QName qName) 
    { 
     if (fixupMap.containsKey(qName.uri)) 
      qName.uri = fixupMap.get(qName.uri); 
     return super.createElementNode(qName); 
    }  
} 

Các nơi khác, bạn có thể phân tích thành một tài liệu DOM :

DOMParse p = new MyDOMParser(...); 
p.parse(new InputSource(inputStream)); 
Document doc = p.getDocument(); 
0

Mã tài liệu DOM sẽ trả về một tài liệu DOM mới trong đó một bộ bản dịch URI không gian tên đã được áp dụng (uriMap). Các khóa phải là các URI trong tài liệu nguồn, các giá trị các URI thay thế trong tài liệu đích. URI không gian tên không xác định đi qua không thay đổi.Nó biết để thay đổi giá trị của xmlns: * thuộc tính, nhưng sẽ không thay đổi các thuộc tính khác có thể xảy ra để có URI không gian tên như giá trị của họ (ví dụ XSD targetNamespace)

private static Node makeClone(Node kid, Node to, Map<String, String> uriMap) { 
    Document doc = to.getNodeType() == Node.DOCUMENT_NODE ? 
      (Document) to : 
      to.getOwnerDocument(); 
    if (kid.getNodeType() == Node.ELEMENT_NODE) { 
     String newURI = 
       uriMap.containsKey(kid.getNamespaceURI()) ? 
       uriMap.get(kid.getNamespaceURI()) : 
       kid.getNamespaceURI(); 
     Element clone = doc.createElementNS(newURI, kid.getNodeName()); 
     to.appendChild(clone); 
     for (int i = 0; i < kid.getAttributes().getLength(); i++) { 
     Attr attr = (Attr) kid.getAttributes().item(i); 
     String newAttrURI = 
       uriMap.containsKey(attr.getNamespaceURI()) ? 
       uriMap.get(attr.getNamespaceURI()) : 
       attr.getNamespaceURI(); 
     String newValue = attr.getValue(); 
     if (attr.getNamespaceURI() != null && 
       attr.getNamespaceURI().equals(
       "http://www.w3.org/2000/xmlns/") && 
       uriMap.containsKey(attr.getValue())) 
      newValue = uriMap.get(attr.getValue()); 
     clone.setAttributeNS(newAttrURI, attr.getNodeName(), newValue); 
     } 
     return clone; 
    } 
    Node clone = kid.cloneNode(false); 
    doc.adoptNode(clone); 
    to.appendChild(clone); 
    return clone; 
} 

private static void copyKidsChangingNS(Node from, Node to, 
     Map<String, String> uriMap) { 
    NodeList kids = from.getChildNodes(); 
    for (int i = 0; i < kids.getLength(); i++) { 
     Node kid = kids.item(i); 
     Node clone = makeClone(kid, to, uriMap); 
     copyKidsChangingNS(kid, clone, uriMap); 
    } 
} 

public static Document changeDocNS(Document doc, Map<String, String> uriMap) 
     throws Exception { 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    dbf.setNamespaceAware(true); 
    DocumentBuilder db = dbf.newDocumentBuilder(); 
    Document newDoc = db.newDocument(); 
    copyKidsChangingNS(doc, newDoc, uriMap); 
    return newDoc; 
} 
Các vấn đề liên quan