Обработка на XML документи в Java с помощта на XPath и XSLT

Разширимият език за маркиране (XML) със сигурност е една от най-горещите технологии в момента. Въпреки че концепцията за езиците за маркиране не е нова, XML изглежда особено привлекателна за програмистите на Java и Интернет. Java API за XML парсинг (JAXP; вижте Ресурси), след като наскоро беше дефиниран чрез Java Community Process, обещава да осигури общ интерфейс за достъп до XML документи. W3C е дефинирал т. Нар. Document Object Model (DOM), който осигурява стандартен интерфейс за работа с XML документ в дървовидна йерархия, докато Simple API за XML (SAX) позволява на програма да анализира XML документ последователно, на базата на върху модел за обработка на събития. И двата стандарта (SAX е де факто стандарт) допълват JAXP. Заедно тези три API осигуряват достатъчна поддръжка за работа с XML документи в Java,и множество книги на пазара описват използването им.

Тази статия представя начин за обработка на XML документи, който надхвърля стандартните Java API за манипулиране на XML. Ще видим, че в много случаи XPath и XSLT предоставят по-прости и по-елегантни начини за решаване на проблеми с приложенията. В някои прости проби ще сравним чисто Java / XML решение с такова, което използва XPath и / или XSLT.

И XSLT, и XPath са част от спецификацията за разширяем език на стилове (XSL) (вж. Ресурси). XSL се състои от три части: самата спецификация на езика XSL, XSL трансформации (XSLT) и XML Path Language (XPath). XSL е език за трансформиране на XML документи; включва дефиниция - Форматиране на обекти - за това как XML документите могат да бъдат форматирани за представяне. XSLT определя речник за трансформиране на един XML документ в друг. Можете да считате XSLT за XSL минус форматиращи обекти. Езикът XPath адресира конкретни части от XML документи и е предназначен да се използва от таблица със стилове XSLT.

За целите на тази статия се предполага, че сте запознати с основите на XML и XSLT, както и с DOM API. (За информация и уроци по тези теми вижте Ресурси.)

Забележка: Примерите на кодове на тази статия са съставени и тествани с анализатора Apache Xerces XML и процесора Apache Xalan XSL (вж. Ресурси).

Проблемът

Много статии и статии, които се занимават с XML, твърдят, че това е идеалното средство за постигане на добра дизайнерска практика в уеб програмирането: модел на модел-изглед-контролер (MVC) или, по-просто казано, разделяне на данните от приложението от данните от презентацията . Ако данните на приложението са форматирани в XML, те могат лесно да бъдат обвързани - обикновено в сървлет или Java ServerPage -, да речем, HTML шаблони, като се използва XSL таблица със стилове.

Но XML може да направи много повече от обикновена помощ при разделяне на изглед на модел за интерфейс на приложение. Понастоящем наблюдаваме все по-широко използване на компоненти (например компоненти, разработени с помощта на стандарта EJB), които могат да се използват за сглобяване на приложения, като по този начин се повишава производителността на разработчиците. Повторната употреба на компоненти може да бъде подобрена чрез форматиране на данните, с които компонентите се справят по стандартен начин. Всъщност можем да очакваме да виждаме все повече и повече публикувани компоненти, които използват XML, за да опишат своите интерфейси.

Тъй като XML-форматираните данни са езиково неутрални, те стават използваеми в случаите, когато клиентът на дадена услуга за приложения не е известен или когато не трябва да има никакви зависимости на сървъра. Например в B2B среди може да не е приемливо две страни да имат зависимости от конкретни интерфейси на обект Java за обмен на данни. Новите технологии като протокола за прост достъп до обекти (SOAP) (вж. Ресурси) отговарят на тези изисквания.

Всички тези случаи имат едно общо нещо: данните се съхраняват в XML документи и трябва да бъдат манипулирани от приложение. Например приложение, което използва различни компоненти от различни доставчици, най-вероятно ще трябва да промени структурата на данните (XML), за да отговаря на нуждите на приложението или да се придържа към даден стандарт.

Код, написан с помощта на Java API, споменати по-горе, със сигурност би направил това. Освен това има все повече и повече налични инструменти, с които можете да превърнете XML документ в JavaBean и обратно, което улеснява обработката на данните от Java програма. В много случаи обаче приложението или поне част от него просто обработва един или повече XML документи като вход и ги преобразува в различен XML формат като изход. Използването на таблици със стилове в тези случаи е жизнеспособна алтернатива, както ще видим по-нататък в тази статия.

Използвайте XPath за намиране на възли в XML документ

Както беше посочено по-горе, езикът XPath се използва за намиране на определени части от XML документ. Като такъв той е предназначен да се използва от таблица със стилове XSLT, но нищо не ни пречи да го използваме в нашата програма Java, за да избегнем продължителна итерация над йерархията на DOM елемент. Всъщност можем да оставим процесора XSLT / XPath да свърши работата вместо нас. Нека да разгледаме как работи това.

Нека приемем, че имаме сценарий на приложение, при който източник XML документ се представя на потребителя (евентуално след обработка от таблица със стилове). Потребителят прави актуализации на данните и, за да спести мрежовата честотна лента, изпраща само актуализираните записи обратно към приложението. Приложението търси XML фрагмента в изходния документ, който трябва да бъде актуализиран, и го заменя с новите данни.

Ще създадем малка извадка, която ще ви помогне да разберете различните опции. За този пример предполагаме, че приложението се занимава с адресни записи в addressbook. Примерен addressbookдокумент изглежда така:

  John Smith 250 18th Ave SE Rochester MN 55902 Bill Morris 1234 Center Lane NW St. Paul MN 55123   

Приложението (евентуално, макар и не непременно, сървлет) поддържа екземпляр на addressbookв паметта като DOM Documentобект. Когато потребителят промени адрес, интерфейсът на приложението му изпраща само актуализирания елемент.

Най елемент се използва за идентификация на адрес; той служи като първичен ключ. Това не би имало много смисъл за истинско приложение, но го правим тук, за да улесним нещата.

Сега трябва да напишем някакъв Java код, който ще ни помогне да идентифицираме елемента в изходното дърво, който трябва да бъде заменен с актуализирания елемент. В findAddress()метода по-долу показва как това може да бъде постигнато. Моля, обърнете внимание, че за да бъде пробата кратка, ние пропуснахме подходящото обработване на грешки.

публичен възел findAddress (Име на низ, източник на документ) {Корен на елемент = source.getDocumentElement (); NodeList nl = root.getChildNodes (); // итерираме по всички адресни възли и намираме този, който има правилния адресат за (int i = 0; i
   
    

Кодът по-горе би могъл най-вероятно да бъде оптимизиран, но е очевидно, че итерацията през DOM дървото може да бъде досадна и податлива на грешки. Сега нека разгледаме как целевият възел може да бъде разположен с помощта на прост израз на XPath. Изявлението може да изглежда така:

// адрес [дете :: адресат [текст () = 'Джим Смит]]] 

Вече можем да пренапишем предишния си метод. Този път използваме оператора XPath, за да намерим желания възел:

публичен възел findAddress (име на низ, източник на документ) хвърля изключение {// трябва да пресъздадете няколко помощни обекта XMLParserLiaison xpathSupport = нов XMLParserLiaisonDefault (); XPathProcessor xpathParser = нов XPathProcessorImpl (xpathSupport); PrefixResolver prefixResolver = нов PrefixResolverDefault (source.getDocumentElement ()); // създаваме XPath и го инициализираме XPath xp = new XPath (); String xpString = "// адрес [дете :: адресат [текст () = '" + име + "']]"; xpathParser.initXPath (xp, xpString, prefixResolver); // сега изпълняваме оператора за избор на XPath XObject list = xp.execute (xpathSupport, source.getDocumentElement (), prefixResolver); // връщаме получения списък за връщане на възела.nodeset (). item (0); }

The above code may not look a lot better than the previous try, but most of this method's contents could be encapsulated in a helper class. The only part that changes over and over is the actual XPath expression and the target node.

This lets us create an XPathHelper class, which looks like this:

import org.w3c.dom.*; import org.xml.sax.*; import org.apache.xalan.xpath.*; import org.apache.xalan.xpath.xml.*; public class XPathHelper { XMLParserLiaison xpathSupport = null; XPathProcessor xpathParser = null; PrefixResolver prefixResolver = null; XPathHelper() { xpathSupport = new XMLParserLiaisonDefault(); xpathParser = new XPathProcessorImpl(xpathSupport); } public NodeList processXPath(String xpath, Node target) thrws SAXException { prefixResolver = new PrefixResolverDefault(target); // create the XPath and initialize it XPath xp = new XPath(); xpathParser.initXPath(xp, xpath, prefixResolver); // now execute the XPath select statement XObject list = xp.execute(xpathSupport, target, prefixResolver); // return the resulting node return list.nodeset(); } } 

After creating the helper class, we can rewrite our finder method again, which is now very short:

public Node findAddress(String name, Document source) throws Exception { XPathHelper xpathHelper = new XPathHelper(); NodeList nl = xpathHelper.processXPath( "//address[child::addressee[text() = '"+name+"']]", source.getDocumentElement()); return nl.item(0); } 

The helper class can now be used whenever a node or a set of nodes needs to be located in a given XML document. The actual XPath statement could even be loaded from an external source, so that changes could be made on the fly if the source document structure changes. In this case, no recompile is necessary.

Process XML documents with XSL stylesheets

In some cases, it makes sense to outsource the entire handling of an XML document to an external XSL stylesheet, a process in some respects similar to the use of XPath as described in the previous section. With XSL stylesheets, you can create an output document by selecting nodes from the input document and merging their content with stylesheet content, based on pattern rules.

If an application changes the structure and content of an XML document and producing a new document, it may be better and easier to use a stylesheet to handle the work rather than writing a Java program that does the same job. The stylesheet is most likely stored in an external file, allowing you to change it on the fly, without the need to recompile.

Например, бихме могли да извършим обработката за addressbookпробата, като създадем таблица със стилове, която обединява кешираната версия на addressbookс актуализираната, като по този начин създаваме нов документ с актуализациите в него.

Ето пример за такъв стил:

   //mymachine.com/changed.xml