שינוי תכונת XML ב- Java

1. הקדמה

פעילות נפוצה אחת כשאנחנו עובדים עם XML היא עבודה עם התכונות שלה. במדריך זה נחקור כיצד לשנות תכונת XML באמצעות Java.

2. תלות

על מנת להריץ את הבדיקות, נצטרך להוסיף את ה- JUnit ו- xmlunit-assertj תלות בפרויקט Maven שלנו:

 מבחן org.junit.jupiter junit-jupiter 5.5.0 
 מבחן org.xmlunit xmlunit-assertj 2.6.3 

3. שימוש ב- JAXP

נתחיל במסמך XML:

  [דוא"ל מוגן] [דוא"ל מוגן] 

כדי לעבד את זה, אנחנו השתמש ב- Java API לעיבוד XML (JAXP), שאוגד עם Java מאז גרסת 1.4.

בואו לשנות את צרכן לייחס ולשנות את ערכו ל- שֶׁקֶר.

ראשית, עלינו לבנות א מסמך אובייקט מקובץ ה- XML, וכדי לעשות זאת, נשתמש ב- DocumentBuilderFactory:

DocumentBuilderFactory מפעל = DocumentBuilderFactory.newInstance (); factory.setFeature (XMLConstants.FEATURE_SECURE_PROCESSING, נכון); factory.setFeature ("// apache.org/xml/features/disallow-doctype-decl", נכון); קלט מסמך = מפעל .newDocumentBuilder () .parse (resourcePath);

שים לב שכדי השבת עיבוד ישויות חיצוניות (XXE) בשביל ה DocumentBuilderFactory מעמד, אנו מגדירים את XMLConstants.FEATURE_SECURE_PROCESSING ו //apache.org/xml/features/disallow-doctype-decl תכונות. זה נוהג טוב להגדיר את זה כשאנחנו מנתחים קבצי XML לא מהימנים.

לאחר אתחול שלנו קֶלֶט אובייקט, נצטרך לאתר את הצומת עם התכונה שברצוננו לשנות. בואו נשתמש בביטוי XPath כדי לבחור אותו:

XPath xpath = XPathFactory .newInstance () .newXPath (); מחרוזת expr = String.format ("// * [מכיל (@% s, '% s')]", תכונה, oldValue); צומת NodeList = (NodeList) xpath.evaluate (expr, input, XPathConstants.NODESET);

במקרה זה, ה- XPath להעריך השיטה מחזירה לנו רשימת צומת עם הצמתים המותאמים.

בוא נחזור על הרשימה כדי לשנות את הערך:

עבור (int i = 0; i <nodes.getLength (); i ++) {Element value = (Element) nodes.item (i); value.setAttribute (attribute, newValue); }

או, במקום א ל לולאה, אנחנו יכולים להשתמש ב- IntStream:

IntStream .range (0, nodes.getLength ()) .mapToObj (i -> (Element) nodes.item (i)) .forEach (value -> value.setAttribute (attribute, newValue));

עכשיו, בואו נשתמש ב- שַׁנַאי התנגד ליישם את השינויים:

מפעל TransformerFactory = TransformerFactory.newInstance (); factory.setFeature (XMLConstants.FEATURE_SECURE_PROCESSING, נכון); שנאי xformer = factory.newTransformer (); xformer.setOutputProperty (OutputKeys.INDENT, "כן"); פלט סופר = StringWriter חדש (); xformer.transform (DOMSource חדש (קלט), StreamResult חדש (פלט));

אם נדפיס את תְפוּקָה תוכן אובייקט, נקבל את ה- XML ​​המתקבל עם ה- צרכן מאפיין שונה:

  [דוא"ל מוגן] [דוא"ל מוגן] 

כמו כן, אנו יכולים להשתמש ב- טוענים כי שיטת XMLUnit אם עלינו לאמת זאת במבחן יחידה:

assertThat (output.toString ()). hasXPath ("// * [מכיל (@customer, 'false')]");

4. שימוש ב- dom4j

dom4j היא מסגרת קוד פתוח לעיבוד XML שמשולבת ב- XPath ותומכת באופן מלא באוספי DOM, SAX, JAXP ו- Java.

4.1. תלות של Maven

עלינו להוסיף את התלות dom4j ו- jaxen שלנו pom.xml להשתמש ב- dom4j בפרויקט שלנו:

 org.dom4j dom4j 2.1.1 jaxen jaxen 1.2.0 

אנו יכולים ללמוד עוד על dom4j במאמר התמיכה שלנו בספריות XML.

4.2. באמצעות org.dom4j.Element.addAttribute

dom4j מציע את אֵלֵמֶנט ממשק כהפשטה עבור אלמנט XML. נשתמש ב- addAttribute שיטה לעדכן שלנו צרכן תְכוּנָה.

בואו נראה איך זה עובד.

ראשית, עלינו לבנות א מסמך אובייקט מקובץ ה- XML ​​- הפעם נשתמש ב- SAXReader:

SAXReader xmlReader = SAXReader חדש (); קלט מסמך = xmlReader.read (resourcePath); xmlReader.setFeature ("// apache.org/xml/features/disallow-doctype-decl", נכון); xmlReader.setFeature ("// xml.org/sax/features/external-general-entities", שקר); xmlReader.setFeature ("// xml.org/sax/features/external-parameter-entities", שקר);

קבענו את התכונות הנוספות על מנת למנוע XXE.

כמו JAXP, אנו יכולים להשתמש בביטוי XPath כדי לבחור את הצמתים:

מחרוזת expr = String.format ("// * [מכיל (@% s, '% s')]", תכונה, oldValue); XPath xpath = DocumentHelper.createXPath (expr); צמתים ברשימה = xpath.selectNodes (קלט);

כעת נוכל לחזור ולעדכן את התכונה:

עבור (int i = 0; i <nodes.size (); i ++) {Element Element = (Element) nodes.get (i); element.addAttribute (attribute, newValue); }

שים לב כי בשיטה זו, אם כבר קיים תכונה לשם הנתון, היא תוחלף. אחרת, זה יתווסף.

על מנת להדפיס את התוצאות, אנו יכולים לעשות שימוש חוזר בקוד מהסעיף הקודם של JAXP.

5. שימוש ב- jOOX

jOOX (jOOX XML מונחה עצמים) הוא עטיפה עבור ה- org.w3c.dom חבילה המאפשרת יצירת מסמכי XML שוטפים ומניפולציות במקום בו נדרשת DOM אך מילולית מדי. jOOX עוטף את המסמך הבסיסי בלבד וניתן להשתמש בו לשיפור DOM, ולא כחלופה.

5.1. תלות של Maven

עלינו להוסיף את התלות שלנו pom.xml להשתמש ב- jOOX בפרויקט שלנו.

לשימוש עם Java 9+, אנו יכולים להשתמש ב:

 org.jooq joox 1.6.2 

או עם Java 6+ יש לנו:

 org.jooq joox-java-6 1.6.2 

אנו יכולים למצוא את הגרסאות העדכניות ביותר של ג'וקס ו joox-java-6 במאגר Maven Central.

5.2. באמצעות org.w3c.dom.Element.setAttribute

ממשק ה- API של jOOX עצמו הוא בהשראת jQuery, כפי שניתן לראות בדוגמאות שלהלן. בואו נראה איך להשתמש בזה.

ראשית, עלינו לטעון את מסמך:

בונה DocumentBuilder = JOOX.builder (); קלט מסמך = builder.parse (resourcePath);

כעת, עלינו לבחור אותו:

התאמה $ = $ (קלט);

על מנת לבחור את אלמנט הלקוח, אנחנו יכולים להשתמש ב- למצוא שיטה או ביטוי XPath. בשני המקרים נקבל רשימה של האלמנטים התואמים אותה.

בוא נראה את למצוא שיטה בפעולה:

$ .find ("to") .get () .stream () .forEach (e -> e.setAttribute (attribute, newValue));

כדי לקבל את התוצאה כ- חוּט, אנחנו פשוט צריכים להתקשר ל toString () שיטה:

$ .toString ();

6. אמת מידה

על מנת להשוות את הביצועים של ספריות אלה, השתמשנו במבחן JMH.

בואו נראה את התוצאות:

| יחידות שגיאה בציון מצב ציון | | ------------------------------------------------- ------------------- | | AttributeBenchMark.dom4jBenchmark avgt 5 0.150 ± 0.003 ms / op | | AttributeBenchMark.jaxpBenchmark avgt 5 0.166 ± 0.003 ms / op | | AttributeBenchMark.jooxBenchmark avgt 5 0.230 ± 0.033 ms / op |

כפי שאנו רואים, למקרה השימוש הזה וההטמעה שלנו, ל- dom4j ו- JAXP יש ציונים טובים יותר מ- jOOX.

7. מסקנה

במדריך מהיר זה, הצגנו כיצד לשנות תכונות XML באמצעות JAXP, dom4j ו- jOOX. כמו כן, מדדנו את ביצועי הספריות הללו עם מדד JMH.

כרגיל, כל דגימות הקוד המוצגות כאן זמינות ב- GitHub.