2

I am trying to remove namespace prefixes. I have tried a couple XSLTs but they do not seem to work (will show why after the example).

Example current xml output:

<s:Body     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<ns:GetPriceSet     xmlns:ns="http://abc.org/01/02">
<ns:og>
    <TestElement1   xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
    <TestElement2   xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</ns:og>
</ns:GetPriceSet>
</s:Body>

What I want:

<s:Body     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<GetPriceSet    xmlns="http://abc.org/01/02">
<og>
    <TestElement1   xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
    <TestElement2   xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</og>
</GetPriceSet>
</s:Body>

I tried using both XSLTs from here: How to remove namespace prefix leaving namespace value (XSLT)?

The problem is that the ns: is instead replaced by ns0 and ns1 instead of being removed completely by the XSLTs. So I assume the XSLT needs to be further modified.

Community
  • 1
  • 1
a b
  • 21
  • 1
  • 2
  • Why do you want to remove the prefixes? – John Saunders Mar 10 '14 at 19:14
  • @John, it's because I'm sending a request to an asmx that breaks if the prefixes are included. I have no idea why, I did not create the asmx I am only consuming it. – a b Mar 10 '14 at 19:22
  • No way does an ASMX service break based on prefixes. It uses the same XML parsing technology as the rest of .NET, and does properly understand prefixes. There must be a different problem. – John Saunders Mar 10 '14 at 19:26
  • The only possible exception to that would be if the service is processing the XML "by hand" and doing it incorrectly. – John Saunders Mar 10 '14 at 19:26
  • John you are probably right, but I have to fit with the parameters that work and they are not going to rewrite their service just to accommodate a request that includes the prefixes. I am currently trying the two solutions posted below. I know that the prefix-less version works from testing it in SoapUI. – a b Mar 10 '14 at 19:29
  • @JohnSaunders this isn't simply "removing the prefix" - the current and wanted examples are semantically different as currently the `TestElement1` and `TestElement2` elements are in _no_ namespace whereas in the wanted output they are in the `http://abc.org/01/02` namespace instead. – Ian Roberts Mar 10 '14 at 19:29
  • As @IanRoberts says, this is not just a case of removing the prefix. I think you probably have certain elements in the wrong namespace, and prefix is not actually the problem. – John Saunders Mar 10 '14 at 20:13
  • I'm trying to get the elements in the right namespace and also remove the prefix because for whatever reason the service will not work with prefixes. Has been tested several times with a request w/ prefixes and one without (the request w/ prefixes had the ns prefix on the TestElements and other children elements that I removed for sake of brevity). Removing the namespaces is also the solution that the service author gave me. They are not going to be able to fix the service so that it can properly consume well written xml, hence my unusual request. – a b Mar 10 '14 at 20:18
  • Are you using the libxslt processor? – michael.hor257k Mar 12 '14 at 05:50

4 Answers4

0

Based on the example you shared, it seems this should work?

<xsl:template match="ns:*">
        <xsl:element name="{local-name()}" >
            <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
    </xsl:template>
gtr1971
  • 2,672
  • 2
  • 18
  • 23
0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:ns="http://abc.org/01/02">
    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8" standalone="yes"/>



<xsl:template match="ns:*">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="@* | *"/>
    </xsl:element>
 </xsl:template>

<xsl:template match="* | @*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
deanosaur
  • 621
  • 3
  • 5
  • Just tried this, however it removes the namespace tag from so it appears as instead of – a b Mar 10 '14 at 19:50
0

In XML terms the only (semantic) difference between your current and wanted outputs is that in the current output you have TestElement1 and TestElement2 that are not in a namespace, and in your wanted output they have been moved into the same namespace as their parent og element. So it may be sufficient for you to do something like

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="ns:og/*" xmlns:ns="http://abc.org/01/02">
    <xsl:element name="ns:{local-name()}">
      <xsl:apply-templates select="node() | @*"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

which should produce output of

<s:Body     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<ns:GetPriceSet     xmlns:ns="http://abc.org/01/02">
<ns:og>
    <ns:TestElement1   xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
    <ns:TestElement2   xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</ns:og>
</ns:GetPriceSet>
</s:Body>

and this is the same as your "wanted" output as far as a namespace-aware XML parser is concerned.

If in the real example your TestElements have children then you may need to match ns:og//* instead of just ns:og/* with the second template.

If the service that is consuming your XML is choking on the prefixes (in which case it shouldn't claim that it can handle XML, but that's another argument...) then it is possible to move everything under the s:Body into the target namespace without any prefixes if you replace the second template as follows:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="s:Body//*" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <xsl:element name="{local-name()}" namespace="http://abc.org/01/02">
      <xsl:apply-templates select="node() | @*"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Hi Ian, this looks right in theory but it will break the request to the asmx because of the prefixes. I know it sounds strange. Actually the original xml looked like what your produced output looks like but I use functx xquery functions to strip the prefix. Problem is that it doesn't affect the top two elements (GetPriceSet and og) and I need to modify those two to get this to work. Ideally I need my output to look like how I have it in the question. – a b Mar 10 '14 at 19:52
  • @ab Then they're clearly not using a real XML parser. I wonder if it would complain equally if your WS toolkit happens to use `` instead of ``. Anyway, I've added an alternative that should put things in the right namespace _without_ prefixes, see if that's any more successful. – Ian Roberts Mar 10 '14 at 19:58
  • I'll admit I did get a prefix-dependent bug once years ago when I implemented a SAX [ContentHandler](http://docs.oracle.com/javase/7/docs/api/org/xml/sax/ContentHandler.html) and accidentally got the qname and localName parameters the wrong way round... They may have done something similar, certainly it's a bug that's worth you reporting to them. – Ian Roberts Mar 10 '14 at 20:02
  • hi Ian, for this solution did you mean for me to include both xsl:templates? (the one for ns:og//* and the one for s:Body//*) Or just the s:Body//* one? I tried with both and it ended up substituting ns with ns2, ns3, ns4, ns5, etc. on every element. – a b Mar 10 '14 at 20:23
  • @ab I meant the `s:Body//*` one _instead of_ the `ns:og/*` one. I've updated to make it clearer – Ian Roberts Mar 10 '14 at 20:40
0

This produces exactly what you want! (let me know if it's not!)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:foobar="http://abc.org/01/02">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

<xsl:template match="foobar:* | TestElement1 | TestElement2">
    <xsl:element name="{local-name()}" namespace="http://abc.org/01/02">
        <xsl:apply-templates select="node() | @*"  />
    </xsl:element>
 </xsl:template>

<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
Nick Grealy
  • 24,216
  • 9
  • 104
  • 119