Steven Yong
Steven Yong

Reputation: 5426

How do I deal with namespaces in XSLT?

I am new to XSL and would like to transform a NewML G2 format XML into another XML.

For example I have:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- 
- Structure: NML2 SNI Text 
-->
<!-- ========================================================= -->
<newsMessage xmlns="http://iptc.org/std/nar/2006-10-01/" xmlns:rtr="http://www.reuters.com/ns/2003/08/content" xmlns:x="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <header>
    <transmitId>tag:123.com,0000:newsml_N19279043:609406403</transmitId>
    <priority>3</priority>
    <destination>ABX</destination>
  </header>
  <itemSet>
    <newsItem conformance="power" guid="tag:reuters.com,0000:newsml_N19279043" standard="NewsML-G2" standardversion="2.1" version="609406403" xml:lang="en">
      <itemMeta>
        <itemClass qcode="icls:text" rtr:msgType="S"/>
        <provider literal="reuters.com"/>
        <versionCreated>2011-05-20T05:00:27.000Z</versionCreated>
      </itemMeta>
      <contentMeta>
        <urgency>3</urgency>
        <infoSource literal="Reuters" role="cRole:origProv"/>
        <subject qcode="N2:BNK"/>
        <headline>My Headline</headline>
        <by>ABC</by>
      </contentMeta>
      <contentSet>
        <inlineXML contenttype="application/xhtml+html" wordcount="881">
          <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
              <title/>
            </head>
            <body>
              <p>Paragraph A</p>
              <p>* Paragraph A</p>
            </body>
          </html>
        </inlineXML>
      </contentSet>
    </newsItem>
  </itemSet>
</newsMessage>

I would like my result XML to be something like:

<?xml version="1.0" encoding="UTF-8"?>
<MyData>
        <MyTransmitId>tag:123.com,0000:newsml_N19279043:609406403</MyTransmitId>
        <MyHeadline>My Headline</MyHeadline>
        <MyContent>
          <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
              <title/>
            </head>
            <body>
              <p>Paragraph A</p>
              <p>* Paragraph A</p>
            </body>
          </html>
        </MyContent>
</MyData>

I come out with the following XSL:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" indent="yes" encoding="utf-8" />
    <xsl:template match="/newsMessage">
    <MyTransmitId>
      <xsl:value-of select="header/transmitId"/>
        </MyTransmitId>
    <MyHeadline>
      <xsl:value-of select="itemSet/newsItem/contentMeta/headline"/>
    </MyHeadline>
    <MyContent>
      <xsl:value-of select="itemSet/newsItem/contentSet/inlineXML"/>
    </MyContent>
  </xsl:template>
</xsl:stylesheet>

However it transforms to something not quite right. And I noticed it is because of the element

<newsMessage xmlns="http://iptc.org/std/nar/2006-10-01/" xmlns:rtr="http://www.reuters.com/ns/2003/08/content" xmlns:x="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

If I change it to the below then my XSL will work:

<newsMessage>

How do I transform the element newsMessage with the namespaces properly?

Thank you very much.

Upvotes: 1

Views: 2748

Answers (3)

Steven Yong
Steven Yong

Reputation: 5426

I found another solution to this one, posting here for the benefits of others :)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" media-type="text/html"/>
    <xsl:template match="/">
        <xsl:element name="MyData">
            <xsl:element name="MyTransmitId">
                <xsl:value-of select="//*[name()='transmitId']"/>
            </xsl:element>
            <xsl:element name="MyHeadline">
                <xsl:value-of select="//*[name()='headline']"/>
            </xsl:element>
            <xsl:element name="MyContent">
                <xsl:copy-of select="//*[name()='inlineXML']/*"/>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

alexbrn
alexbrn

Reputation: 2155

A couple of problems here:

First, much of your source document is in the Namespace named "http://iptc.org/std/nar/2006-10-01/", and you need to take this into account when referencing that content in your XSLT. In the stylesheet below I have done that by binding this Namespace to the prefix "itpc", and then using that in the XPath expressions.

Secondly, you want the XHTML content structure to be copied into your result, and you need to use <xsl:copy-of> (not value-of) to do that — in fact you need to get the content of your inlineXML element, rather than it itself; I have modified the XPath accordingly.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:itpc="http://iptc.org/std/nar/2006-10-01/">
    <xsl:output method="xml" indent="yes" encoding="utf-8"/>
    <xsl:template match="/itpc:newsMessage">
        <MyTransmitId>
            <xsl:value-of
                select="itpc:header/itpc:transmitId"/>
        </MyTransmitId>
        <MyHeadline>
            <xsl:value-of
                select="itpc:itemSet/itpc:newsItem/itpc:contentMeta/itpc:headline"/>
        </MyHeadline>
        <MyContent>
            <xsl:copy-of
                select="itpc:itemSet/itpc:newsItem/itpc:contentSet/itpc:inlineXML/*"/>
        </MyContent>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 4

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798436

Declare the namespace and use it.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt" xmlns:nar="http://iptc.org/std/nar/2006-10-01/">
 ...
    <xsl:template match="/nar:newsMessage">
     ...

Upvotes: 1

Related Questions