سؤال

انا املك XmlDocument في جافا، تم إنشاؤها باستخدام Weblogic XmlDocument محلل.

أريد استبدال محتوى العلامة في هذا XMLDocument ببياناتي الخاصة، أو أدخل العلامة إذا لم تكن موجودة.

<customdata>
   <tag1 />
   <tag2>mfkdslmlfkm</tag2>
   <location />
   <tag3 />
</customdata>

أريد على سبيل المثال إدراج بعض عناوين URL في علامة الموقع:

<location>http://something</location>

لكن بخلاف ذلك اترك XML كما هو.

حاليا أستخدم أ XMLCursor:

    XmlObject xmlobj = XmlObject.Factory.parse(a.getCustomData(), options);
    XmlCursor xmlcur = xmlobj.newCursor();

    while (xmlcur.hasNextToken()) {
      boolean found = false;
      if (xmlcur.isStart() && "schema-location".equals(xmlcur.getName().toString())) {
        xmlcur.setTextValue("http://replaced");
        System.out.println("replaced");
        found = true;
      } else if (xmlcur.isStart() && "customdata".equals(xmlcur.getName().toString())) {
        xmlcur.push();
      } else if (xmlcur.isEnddoc()) {
        if (!found) {
          xmlcur.pop();
          xmlcur.toEndToken();
          xmlcur.insertElementWithText("schema-location", "http://inserted");
          System.out.println("inserted");
        }

      }
      xmlcur.toNextToken();
    }

حاولت العثور على "سريع" xquery طريقة للقيام بذلك منذ XmlDocument لديه execQuery الطريقة، ولكن لم أجدها سهلة للغاية.

هل لدى أحد طريقة أفضل من هذه؟يبدو الأمر معقدًا بعض الشيء.

هل كانت مفيدة؟

المحلول

ماذا عن النهج القائم على XPath؟أنا أحب هذا النهج لأن المنطق سهل الفهم للغاية.الكود يوثق نفسه إلى حد كبير.

إذا كان مستند XML الخاص بك متاحًا لك ككائن org.w3c.dom.Document (كما يعود معظم المحللين)، فيمكنك القيام بشيء مثل ما يلي:

// get the list of customdata nodes
NodeList customDataNodeSet = findNodes(document, "//customdata" );

for (int i=0 ; i < customDataNodeSet.getLength() ; i++) {
  Node customDataNode = customDataNodeSet.item( i );

  // get the location nodes (if any) within this one customdata node
  NodeList locationNodeSet = findNodes(customDataNode, "location" );

  if (locationNodeSet.getLength() > 0) {
    // replace
    locationNodeSet.item( 0 ).setTextContent( "http://stackoverflow.com/" );
  }
  else {
    // insert
    Element newLocationNode = document.createElement( "location" );
    newLocationNode.setTextContent("http://stackoverflow.com/" );
    customDataNode.appendChild( newLocationNode );
  }
}

وإليك الطريقة المساعدة findNodes التي تقوم بالبحث عن XPath.

private NodeList findNodes( Object obj, String xPathString )
  throws XPathExpressionException {

  XPath xPath = XPathFactory.newInstance().newXPath();
  XPathExpression expression = xPath.compile( xPathString );
  return (NodeList) expression.evaluate( obj, XPathConstants.NODESET );
}

نصائح أخرى

ماذا عن النهج الموجه للكائنات؟يمكنك إلغاء تسلسل XML إلى كائن، وتعيين قيمة الموقع على الكائن، ثم إجراء تسلسل مرة أخرى إلى XML.

XStream يجعل هذا سهلا حقا.

على سبيل المثال، يمكنك تحديد الكائن الرئيسي، والذي في حالتك هو CustomData (أنا أستخدم الحقول العامة لإبقاء المثال بسيطًا):

public class CustomData {
  public String tag1;
  public String tag2;
  public String location;
  public String tag3;
}

ثم تقوم بتهيئة XStream:

XStream xstream = new XStream();
// if you need to output the main tag in lowercase, use the following line
xstream.alias("customdata", CustomData.class);  

يمكنك الآن إنشاء كائن من XML، وتعيين حقل الموقع على الكائن وإعادة إنشاء XML:

CustomData d = (CustomData)xstream.fromXML(xml);
d.location = "http://stackoverflow.com";
xml = xstream.toXML(d);

كيف يبدو هذا؟

إذا كنت لا تعرف المخطط، فربما لا يكون حل XStream هو الحل الأمثل.على الأقل XStream موجود على رادارك الآن، وقد يكون مفيدًا في المستقبل!

يجب أن تكون قادرًا على القيام بذلك مع query

يحاول

 fn:replace(string,pattern,replace)

أنا شخصيًا جديد على استخدام xquery ووجدت أنها لغة استعلام مؤلمة للعمل بها، لكنها تعمل بشكل جيد بمجرد تجاوز منحنى التعلم الأولي.

ما زلت أتمنى أن تكون هناك طريقة أسهل تتسم بنفس الكفاءة؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top