Laboratorium XML
wtorek 11.00—12.30
»Home
»Materiały
  »DTD & co.
  »SAX
  »DOM
  »Zadanie 2
  »XPath
  »XSLT
  »Simple
  »JDOM
  »JS
»Odnośniki
  »Xerces2
»Zadania

XSL Transformations (XSLT)

Gandalf Reloaded

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/xhtml1/strict">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>
  <xsl:template match="/">
    <html>
      <head>
        <title>Napewno strict wymaga</title>
      </head>
      <body>
        <xsl:variable name="player-character" select="//before/@character"/>
        <p>
          Siła postaci
          <xsl:value-of select="descendant::before/attribute::character"/>
          <xsl:text>: </xsl:text>
          <xsl:value-of select="id($player-character)/child::strength/child::text()"/>
          <!-- converted as with string() -->
        </p>
        <p>
          Siła postaci
          <xsl:value-of select="$player-character"/>
          <xsl:text>: </xsl:text>
          <xsl:value-of select="id($player-character)/strength"/>
          <!-- converted as with string() -->
        </p>
      </body>
    </html>
</xsl:template>
</xsl:stylesheet>

wykonujemy transformację na dokumencie moria-example.xml

$ xsltproc moria2.xsl moria-example.xml

i otrzymujemy

<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/TR/xhtml1/strict">
  <head>
    <title>Napewno strict wymaga</title>
  </head>
  <body>
    <p>
          Siła postaci
          Gandalf: 40</p>
    <p>
          Siła postaci
          Gandalf: 40</p>
  </body>
</html>

Przygotowanie danych

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:a="http://example.com/zamowienia"
                xmlns="http://example.com/zamowienia"
                exclude-result-prefixes="a">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>

  <xsl:template match="/">
    <artykuly>
<!--       <xsl:copy-of select="//a:artykul"/> -->

<!-- xsl:copy copies just the node no attributes no children -->

      <xsl:for-each select="//a:artykul">
        <xsl:copy-of "."/>
      </xsl:for-each>
    </artykuly>
  </xsl:template>

</xsl:stylesheet>

orders.xml

Wyświetlanie danych

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:a="http://example.com/zamowienia"
                xmlns="http://www.w3.org/1999/xhtml"
                exclude-result-prefixes="a">
  <xsl:output method="xml" indent="yes" encoding="utf-8"
              omit-xml-declaration="yes"/>

  <xsl:template match="/">
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      </head>
      <body>
        <h1>Książki</h1>
        <table>
          <xsl:for-each select="//a:książka">
            <xsl:sort  data-type="number" select="a:rok-wydania" order="descending"/>
            <tr>
              <xsl:if test="(position() - 1) mod 6 &lt; 3">
                <xsl:attribute name="bgcolor">#e0e0e0</xsl:attribute>
              </xsl:if>
              <td align="right"><xsl:value-of select="position()"/></td>
              <td><xsl:value-of select="a:autor"/></td>
              <td>
                <a>
                  <xsl:attribute name="href">
                    <xsl:text>iteminfo?id=</xsl:text>
                    <xsl:value-of select="../@id"/>
                  </xsl:attribute>
                  <xsl:apply-templates select="a:tytuł"/>
                </a>
              </td>
              <td><xsl:value-of select="a:rok-wydania"/></td>
            </tr>
          </xsl:for-each>
          </table>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="a:emph">
    <i><xsl:apply-templates/></i>
  </xsl:template>

<!--   <xsl:template match="text()"/> -->

</xsl:stylesheet>
  1. Nazwane wzorce

        <xsl:call-template name="articles-table">
          <xsl:with-param name="selection" select="//a:cd"/>

<xsl:template name="articles-table">
    <xsl:param name="selection" select="//a:książka"/>

XPath in Java

lxml — pythonic binding for the libxml2 and libxslt libraries

# -*- coding: utf-8 -*-

import sys

from lxml import etree

doc = etree.parse(sys.argv[1])
for s in doc.xpath(u"//a:książka/a:autor/text()",
                   {"a": "http://example.com/zamowienia"}):
    print s
$ python list_book_authors.py orders.xml
Bruce Eckel
Don Brown
Adam Mickiewicz
Jan Brzechwa
Michal Jagiello
Milan Kundera
Tolkien
Orson Scott Card
Julio Cotazar
James Jones
Jan Nowak
Jan Jakis
Dan Brown
Brian W.Kernighan
David Zindell
Stephen King

XPathAPI (Xalan Specific)

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;


class ListBookAuthors
{
    static final String ZAMOWIENIA_NS_URI = "http://example.com/zamowienia";

    public static void main(String args[]) throws Exception
    {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        // join CDATA and TEXT into single TEXT nodes
        factory.setCoalescing(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(args[0]);

        // as namespace resolver
        Document ns_doc = builder.getDOMImplementation().createDocument(
            ZAMOWIENIA_NS_URI, "a:orders", null);
        Element root = ns_doc.getDocumentElement();
        // father namespace-prefix mappings may be added with
        root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
                            "xmlns:foo", ZAMOWIENIA_NS_URI);

        NodeIterator iter = XPathAPI.selectNodeIterator(
            doc.getDocumentElement(), "//a:ksi\u0105\u017cka/a:autor/text()",
            root);
        for (Node node = iter.nextNode();
             node != null;
             node = iter.nextNode()) {
            System.out.println(node.getNodeValue());
        }
    }
}
$ java -classpath /usr/share/java/xalan2.jar:. ListBookAuthors orders.xml
Bruce Eckel
Don Brown
Adam Mickiewicz
Jan Brzechwa
Michal Jagiello
Milan Kundera
Tolkien
Orson Scott Card
Julio Cotazar
James Jones
Jan Nowak
Jan Jakis
Dan Brown
Brian W.Kernighan
David Zindell
Stephen King

JAXP

XXX for now it is GNU JAXP version

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.NodeIterator;


class NamespaceContextMap extends HashMap implements NamespaceContext
{
    public String getNamespaceURI(String prefix)
    {
        Object value = this.get(prefix);
        return (value != null) ? (String)value : XMLConstants.NULL_NS_URI;
    }

    public String getPrefix(String namespace)
    {
        //      throw new RuntimeException("Not implemented");
        return null; // not implemented
    }

    public Iterator getPrefixes(String namespace)
    {
        //throw new RuntimeException("Not implemented");
        return null; // not implemented
    }
}


class VariableMap extends HashMap implements XPathVariableResolver
{
    // this is the only function required by XPathVariableResolver
    public Object resolveVariable(QName var_name)
    {
        if (var_name == null) {
            return new NullPointerException(
                "VariableResolver specifies this exception here");
        } else {
            // returns null if varible is undefined
            return this.get(var_name);
        }
    }

    public void setVariable(QName var_name, Object value)
    {
        this.put(var_name, value);
    }
}


class MyFunctionResolver implements XPathFunctionResolver
{
    static String MY_FUNC_URI = "http://example.com/my-functions";

    static double as_double(Object obj) throws XPathFunctionException
    {
        if (obj instanceof String) {
            return Double.parseDouble((String)obj);
        } else if (obj instanceof Double) {
            return ((Double)obj).doubleValue();
        } else {
            throw new XPathFunctionException(
                "This convertion not yet implemented");
        }
    }

    public XPathFunction resolveFunction(QName func_name, int arity)
    {
        if (func_name == null) {
            throw new NullPointerException("function name is null");
        }
// XXX why caller does not resolve namespaces
//      if (func_name.equals(new QName(MY_FUNC_URI, "greater-equal", "my")) &&
        if (func_name.getLocalPart().equals("greater-equal") &&
            arity == 2) {
            return new XPathFunction() {
                public Object evaluate(java.util.List args) throws XPathFunctionException {
                    if (args.size() == 2) {
                        return new Boolean(
                            MyFunctionResolver.as_double(args.get(0))
                            >= MyFunctionResolver.as_double(args.get(1)));
                    } else {
                        return null;
                    }
                }};
        } else {
            return null;
        }
    }
}


class ListBookAuthorsJAXP
{
    static String ZAMOWIENIA_NS_URI = "http://example.com/zamowienia";

    public static void main(String args[]) throws Exception
    {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        // join CDATA and TEXT into single TEXT nodes
        factory.setCoalescing(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse("orders.xml");

        NamespaceContextMap nc = new NamespaceContextMap();
        nc.put("a", ZAMOWIENIA_NS_URI);

        XPathFactory xp_factory = XPathFactory.newInstance();
        XPath xp = xp_factory.newXPath();
        xp.setNamespaceContext(nc);

        ArrayList nodes;

        nodes = (ArrayList) xp.evaluate("//a:ksi\u0105\u017cka/a:autor/text()",
                                      doc, XPathConstants.NODESET);
        for (int i = 0; i < nodes.size(); i++) {
            System.out.println(((Node)nodes.get(i)).getNodeValue());
        }


        // deklaracja i użycie zmiennych
        System.out.println();
        VariableMap var_map = new VariableMap();
        // "new Integer(1)" does not work? but suggested at:
        // http://xml.apache.org/xalan-j/xpath_apis.html#variableresolver
        // double and string works
        var_map.setVariable(new QName("min_count"), new Double(1));
        xp.setXPathVariableResolver(var_map);
        nodes = (ArrayList) xp.evaluate(
            "//a:ksi\u0105\u017cka[../@ilosc > $min_count]/a:autor/text()",
            doc, XPathConstants.NODESET);
        for (int i = 0; i < nodes.size(); i++) {
            System.out.println(((Node)nodes.get(i)).getNodeValue());
        }


        // deklaracja i użycie funkcji
        System.out.println();
        // XXX not resolved in the call
        nc.put("my", MyFunctionResolver.MY_FUNC_URI);
        xp.setXPathFunctionResolver(new MyFunctionResolver());
        nodes = (ArrayList) xp.evaluate(
            "//a:ksi\u0105\u017cka[ext:greater-equal(number(../@ilosc), '2')]" +
            "/a:autor/text()",
            doc, XPathConstants.NODESET);
        for (int i = 0; i < nodes.size(); i++) {
            System.out.println(((Node)nodes.get(i)).getNodeValue());
        }
    }
}

TrAX — The Transformations API for XML

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;


class HtmlizeOrders
{
    public static void main(String args[]) throws Exception
    {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        // join CDATA and TEXT into single TEXT nodes
        factory.setCoalescing(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse("orders.xml");

        TransformerFactory tfactory = TransformerFactory.newInstance();
        Transformer trans = tfactory.newTransformer(
            new StreamSource("htmlize-orders.xsl"));

        trans.transform(new DOMSource(doc), new StreamResult(System.out));
    }
}