Tag Archives: XML

XSLT: Pull duplicate namespace declarations up towards root node

Sometimes XML becomes a bit weird with namespace declarations all over the place. This XSLT cleans that up. Stumbled upon in a StackOverflow answer I don’t find anymore and put here so I know where to find it in the future.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="@* | text() | processing-instruction() | comment()">
        <xsl:copy/>
    </xsl:template>

    <xsl:template match="*">
        <xsl:copy copy-namespaces="no">
            <xsl:for-each-group group-by="local-name()" select="descendant-or-self::*/namespace::*">
                <xsl:copy-of select="."/>
            </xsl:for-each-group>
            <xsl:apply-templates select="@* , node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Example

Input

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
   <soap:Header>
      <wsa:MessageID soap:mustUnderstand="0">uuid:7fa12310-5db4-11e3-ae24-a3c913f2629d</wsa:MessageID>
      <wsa:To soap:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous/</wsa:To>
   </soap:Header>
   <soap:Body>
      <ns1:getTicket xmlns:ns1="http://api.example.com/some-webservice">
         <cus:msisdn xmlns:cus="http://api.example.com/some-webservice" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">00000000</cus:msisdn>
         <cus:ticket xmlns:cus="http://api.example.com/some-webservice" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">171</cus:ticket>
      </ns1:getTicket>
   </soap:Body>
</soap:Envelope>

Output

<soap:Envelope xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
        xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:ns1="http://api.example.com/some-webservice"
        xmlns:cus="http://api.example.com/some-webservice"
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <wsa:MessageID soap:mustUnderstand="0">uuid:7fa12310-5db4-11e3-ae24-a3c913f2629d</wsa:MessageID>
        <wsa:To soap:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous/</wsa:To>
    </soap:Header>
    <soap:Body>
        <ns1:getTicket>
            <cus:msisdn>00000000</cus:msisdn>
            <cus:ticket>171</cus:ticket>
        </ns1:getTicket>
    </soap:Body>
</soap:Envelope>

If anyone know how to adjust it to also merge the duplicated prefixes ns1 and cus, do let me know 🙂

Pretty print XML on Unix command line

Needed to check some XML output from a CalDAV service so I used curl, which is nice and simple. Only problem was that all the XML came back on a single long unreadable line. Turned out it wasn’t too difficult to get it formatted:

$ curl --digest --user usr:pwd -X PROPFIND  | xmllint --format -

The key part here is of course the piping into xmllint. --format tells it to format the XML and the - tells it to read the XML from standard in. The dash can be swapped with the path to an XML file, if you need to format already downloaded XML.

$ xmllint --format file.xml

Simple pimple dimple 🙂

XSLT: Generate comma-separated string from element values

This is one way to create a comma-separated list of values from a set of elements.

<xsl:for-each select="$orders/cm:Error">
    <xsl:value-of select="cm:errorCode"/>
    <xsl:if test="position() != last()">
        <xsl:text>,</xsl:text>
    </xsl:if>
</xsl:for-each>
<!--source http://stackoverflow.com/a/668850/39321 -->

This is another.

<xsl:for-each select="$elements/Error[1]">
    <xsl:value-of select="errorCode"/>
    <xsl:for-each select="following-sibling::Error">
        <xsl:value-of select="concat(',',errorCode)"/>
    </xsl:for-each>
</xsl:for-each>
<!--source http://stackoverflow.com/a/666600/39321 -->

Simple Meddler scripts for faking web service responses

I recently discovered Meddler which is an HTTP generator based on JScript. Since there were not many samples to find and Google wasn’t really of much help here, I figured I could share the scripts I write here. Maybe it helps someone out, and even more likely, I will probably have to look back at this at some time since I will forget 😛

Continue reading Simple Meddler scripts for faking web service responses

Java: Simple XSLT transformation without external libraries

Here’s how to do a simple XSLT transformation using only classes in vanilla Java 1.5 (maybe even 1.4?), no external libraries or anything. The classes are found in the javax.xml.transform package.

// Create a factory
TransformerFactory tf = TransformerFactory.newInstance();
if (!tf.getFeature(SAXTransformerFactory.FEATURE))
    throw new RuntimeException("Did not find a SAX-compatible TransformerFactory.");
SAXTransformerFactory stf = (SAXTransformerFactory) tf;

// Create a reusable template for the XSLT
Templates xslt = stf.newTemplates(new SourceStream(inputStreamWithXslt));

// Use the template to transform some XML
templates.newTransformer().transform(
        new StreamSource(inputStreamWithXml),
        new StreamResult(System.out));

Source: XML and XSLT Tips and Tricks for Java

XSLT: Clean up duplicate namespaces and namespace declarations

I got an XML file from a web service which had a default namespace and a namespace prefix with equal paths. In addition I had to change the root node which then lost all its defined namespaces. This resulted in various namespaces being redeclared on a bunch of various child elements, while it really should just need to be declared once on the root node.

So, this is how you may do fix this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://api.example.com/schema"
    xmlns:dup="http://api.example.com/schema">

    <!-- Identity template, copies everything -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
   
    <!-- Make all elements with dup prefix use default namespace so we avoid ugly mix of both -->
    <xsl:template match="dup:*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()" />
        </xsl:element>
    </xsl:template>

    <!-- For the document element (top element) -->
    <xsl:template match="/*">
        <xsl:copy>
            <!-- Add namespace to prevent redeclaration on every child element using it -->
            <xsl:namespace name="xsi" select="'http://www.w3.org/2001/XMLSchema-instance'" />
            <!-- Copy attributes and child elements -->
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>