ASG
IBM
Zystems
Cressida
Icon
Netflexity
 
  MQSeries.net
Search  Search       Tech Exchange      Education      Certifications      Library      Info Center      SupportPacs      LinkedIn  Search  Search                                                                   FAQ  FAQ   Usergroups  Usergroups
 
Register  ::  Log in Log in to check your private messages
 
RSS Feed - WebSphere MQ Support RSS Feed - Message Broker Support

MQSeries.net Forum Index » WebSphere Message Broker (ACE) Support » Using an existing namespace for a new element in an XML msg

Post new topic  Reply to topic
 Using an existing namespace for a new element in an XML msg « View previous topic :: View next topic » 
Author Message
simonalexander2005
PostPosted: Wed Mar 10, 2021 7:16 am    Post subject: Using an existing namespace for a new element in an XML msg Reply with quote

Acolyte

Joined: 13 Jun 2016
Posts: 55

Hi,

a minimum example of the type of code I'm talking about looks something like this:

Code:
DECLARE NAMESPACE n1 NAMESPACE 'http://namespace.site/schemes/etc';
CALL CopyEntireMessage();
DECLARE outRootRef REFERENCE TO OutputRoot.XMLNSC.*:MsgRoot;
CREATE FIRSTCHILD OF outRootRef NAMESPACE n1 NAME 'additionalIdElement' VALUE 'additionalIDValue';   


When I pass a message through the flow (parsed as XMLNSC on IIB 10.0.0.21, same behaviour also seen on IIB 9), the message that comes out has `n1` prefixing all of the elements in the message.

An example message as follows:

Before:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2015 sp1 (x64) (http://www.altova.com)-->
<MsgRoot xmlns="http://namespace.site/schemes/etc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://namespace.site/schemes/etc" xsi:schemaLocation="http://namespace.site/schemes/etc Message%20Draft.xsd">
   <MessageHeader>
      <MessageReference>
         <MessageType>1</MessageType>
         <MessageTypeVersion>a</MessageTypeVersion>
         <MessageIdentifier>a</MessageIdentifier>
         <MessageDateTime>2001-12-17T09:30:47Z</MessageDateTime>
      </MessageReference>
      <MessageRoutingID>1</MessageRoutingID>
      <SenderReference>a</SenderReference>
      <Sender>1</Sender>
      <Recipient>1</Recipient>
   </MessageHeader>
   <MessageStatus>1</MessageStatus>
</MsgRoot>


After:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<n1:MsgRoot xmlns="http://namespace.site/schemes/etc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://namespace.site/schemes/etc" xsi:schemaLocation="http://namespace.site/schemes/etc Message%20Draft.xsd">
        <n1:additionalIdElement>additionalIDValue</n1:additionalIdElement>
   <n1:MessageHeader>
      <n1:MessageReference>
         <n1:MessageType>1</n1:MessageType>
         <n1:MessageTypeVersion>a</n1:MessageTypeVersion>
         <n1:MessageIdentifier>a</n1:MessageIdentifier>
         <n1:MessageDateTime>2001-12-17T09:30:47Z</n1:MessageDateTime>
      </n1:MessageReference>
      <n1:MessageRoutingID>1</n1:MessageRoutingID>
      <n1:SenderReference>a</n1:SenderReference>
      <n1:Sender>1</n1:Sender>
      <n1:Recipient>1</n1:Recipient>
   </n1:MessageHeader>
   <n1:MessageStatus>1</n1:MessageStatus>
</n1:MsgRoot>


I assume what is happening is that it is treating my namespace that I define in the ESQL as a different namespace to the one that already exists as the default namespace in the message? From what I've read, ESQL doesn't support the default namespace (and, indeed, if I *don't* specify a namespace on my new element, I get an exception
Quote:
Element must have a namespace specified if there is a default namespace in scope
when I run a message through the flow.

So, what I want to do instead, is to use ESQL to grab the namespace associated with another element - say, the root of the message (MsgRoot); and then tell it to use that namespace for the new element instead.

Can anyone help me with the code to do that? Will that even work? Is there another workaround I can use instead?

Thanks

(I should add that I know the second message with the n1:'s is probably still a valid message, but it's ugly and unexpected behaviour)
Back to top
View user's profile Send private message
timber
PostPosted: Wed Mar 10, 2021 5:29 pm    Post subject: Reply with quote

Grand Master

Joined: 25 Aug 2015
Posts: 1280

First, I need to get the facts straight...

Issue 1:
Your input XML contains two namespace declarations for the same namespace. It's still valid XML, but it is liable to cause confusion (and has done, judging by this question)

Issue 2:
Your assumption about what is happening is false. The name of an ESQL namespace constant does not affect the output document in any way. See Example 1 in this KC page to see how it works: https://www.ibm.com/support/knowledgecenter/en/SSMKHH_10.0.0/com.ibm.etools.mft.doc/ac67194_.html

But...when you don't add that ESQL namespace constant, the output looks 'correct'. So what is going on?
1. Imagine that you comment out the last line of the ESQL. Now the output message tree will be identical to the input message tree. IIB is smart enough to recognise that nothing has changed, and it does not bother to parse and re-serialize the input document.
Result: Output document uses the default namespace, just like the input document.

2. Uncomment the last line. Now IIB must parse and re-serialize the XML document. But which XML declaration will it use when it writes the output document? The result is actually arbitrary (as per the W3C XML specification) but IIB happens to pick the non-empty prefix.
Result: Output document uses 'n1' as the prefix throughout the output document.

Quote:
So, what I want to do instead, is to use ESQL to grab the namespace associated with another element - say, the root of the message (MsgRoot); and then tell it to use that namespace for the new element instead.
Hmm...either you phrased that badly, or you need to take a refresher on XML namespaces. The solution is to remove the redundant namespace declaration from the root tag. You can use the DELETE function to do that.
Back to top
View user's profile Send private message
simonalexander2005
PostPosted: Thu Mar 11, 2021 2:23 am    Post subject: Reply with quote

Acolyte

Joined: 13 Jun 2016
Posts: 55

Thanks for the detailed response.

The reason for the duplicate namespace is something in the XSD that means that this is valid (see Sender and Recipient elements' attribute):

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2015 sp1 (x64) (http://www.altova.com)-->
<MsgRoot xmlns="http://namespace.site/schemes/etc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://namespace.site/schemes/etc" xsi:schemaLocation="http://namespace.site/schemes/etc Message%20Draft.xsd">
   <MessageHeader>
      <MessageReference>
         <MessageType>1</MessageType>
         <MessageTypeVersion>a</MessageTypeVersion>
         <MessageIdentifier>a</MessageIdentifier>
         <MessageDateTime>2001-12-17T09:30:47Z</MessageDateTime>
      </MessageReference>
      <MessageRoutingID>1</MessageRoutingID>
      <SenderReference>a</SenderReference>
      <Sender n1:CI_InstanceNumber="1">1</Sender>
      <Recipient n1:CI_InstanceNumber="1">1</Recipient>
   </MessageHeader>
   <MessageStatus>1</MessageStatus>
</MsgRoot>


But this is not:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2015 sp1 (x64) (http://www.altova.com)-->
<MsgRoot xmlns="http://namespace.site/schemes/etc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://namespace.site/schemes/etc" xsi:schemaLocation="http://namespace.site/schemes/etc Message%20Draft.xsd">
   <MessageHeader>
      <MessageReference>
         <MessageType>1</MessageType>
         <MessageTypeVersion>a</MessageTypeVersion>
         <MessageIdentifier>a</MessageIdentifier>
         <MessageDateTime>2001-12-17T09:30:47Z</MessageDateTime>
      </MessageReference>
      <MessageRoutingID>1</MessageRoutingID>
      <SenderReference>a</SenderReference>
      <Sender CI_InstanceNumber="1">1</Sender>
      <Recipient CI_InstanceNumber="1">1</Recipient>
   </MessageHeader>
   <MessageStatus>1</MessageStatus>
</MsgRoot>



I think the issue is that the xsd schema has
Code:
elementFormDefault="qualified" attributeFormDefault="unqualified"



Anyway, I tried your suggestion of deleting the namespace declaration, but I can't make it work. I've tried:

Code:
DECLARE outRootRef REFERENCE TO OutputRoot.XMLNSC.*:MsgRoot;
DELETE FIELD outRootRef.(XMLNSC.NamespaceDecl)xmlns:n1;
DELETE FIELD outRootRef.n1;
SET outRootRef.(XMLNSC.NamespaceDecl)xmlns:n1 = NULL;


But none of those options work.
Back to top
View user's profile Send private message
simonalexander2005
PostPosted: Thu Mar 11, 2021 2:47 am    Post subject: Reply with quote

Acolyte

Joined: 13 Jun 2016
Posts: 55

OK I have found the code to do the delete:

Code:
DELETE FIELD outRootRef.(XMLNSC.NamespaceDecl)*:n1;


It doesn't feel like a very robust solution though - what if the sending system calls it by a different prefix?

Anyway, now, though, the generated XML is inlining the namespace declarations for the attributes; creating a new one for each attribute:


Code:
<Sender xmlns:NS1="http://www.era.europa.eu/schemes/TAFTSI/5.3" NS1:CI_InstanceNumber="1">1</Sender><Recipient xmlns:NS2="http://www.era.europa.eu/schemes/TAFTSI/5.3" NS2:CI_InstanceNumber="1">1</Recipient>


etc.

Is there any way to tell it not to do it that way?
Back to top
View user's profile Send private message
timber
PostPosted: Thu Mar 11, 2021 11:55 am    Post subject: Reply with quote

Grand Master

Joined: 25 Aug 2015
Posts: 1280

You did not mention the CI_InstanceNumber attribute in your original question. That changes things, but not much.

I hope you know what a 'default namespace' is in an XML document? If not, now would be a good time to do some background reading. A default namespace applies to tags but not to attributes. That's why the sender is defining the 'n1' prefix. Note that the sender could and should have used the prefix 'n1:' throughout the document, instead of using two different prefixes for the same namespace.

There is no mystery about 'something in the XSD'. An XSD specifies the namespace of every tag and every attribute. If the XML document contains an attribute with the wrong namespace, the validator must complain.

Quote:
I tried your suggestion of deleting the namespace declaration, but I can't make it work.
That's because you did not describe the whole problem. That pesky attribute changes things a little
You should delete the default namespace declaration, and retain the xmlns:n1. That will ensure that 'n1' is used throughout the document.

Quote:
what if the sending system calls it by a different prefix
Fair question. You will now be removing the 'other' xmlns attribute, so the risk is different, but it is still there. You need to carefully remove the default namespace declaration that clashes with the one you are (now) retaining.
I think this will do it:
Code:
-- If there is a default namespace declaration that clashes with the existing one...
IF (outRootRef.(XMLNSC.NamespaceDecl)xmlns = 'http://namespace.site/schemes/etc') THEN
    DELETE FIELD outRootRef.(XMLNSC.NamespaceDecl)xmlns
END IF;

Having said all of that...namespace prefixes are not significant and the output document will be valid either way.
Back to top
View user's profile Send private message
simonalexander2005
PostPosted: Fri Mar 12, 2021 2:47 am    Post subject: Reply with quote

Acolyte

Joined: 13 Jun 2016
Posts: 55

Thanks for the detailed explanation of what's going on, that's clear and really helpful.

I have tried deleting the default namespace and, like you say, it's now using n1 everywhere. But I don't really want it to prefix every element with "n1" - I am happy to leave the default namespace in place for all elements - but I want all attributes to use the same namespace and not declare a different one each time.

Is there a way to do that without looping through all attributes and manually assigning them?
Back to top
View user's profile Send private message
timber
PostPosted: Fri Mar 12, 2021 3:28 am    Post subject: Reply with quote

Grand Master

Joined: 25 Aug 2015
Posts: 1280

For all elements and attributes within the same scope, IIB will choose the same prefix for the same namespace URL.
Quote:
But I don't really want it to prefix every element with "n1"
Your preferences are not really the issue. If you have a technical reason behind this preference then you need to explain it. Namespace prefixes are not important. They are just a shorthand for the namespace, and they have no business meaning at all.
Quote:
Is there a way to do that without looping through all attributes and manually assigning them?
I think you're missing the point. Your responsibility is to assign the correct namespace to each tag and attribute in the message tree. IIB undertakes to output a valid XML document representing that message tree.

You would like IIB to preferentially use the default namespace for tags when there is a choice of namespace bindings. I can accept that it might be nice if IIB did that, but it's a pretty rare requirement.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic  Reply to topic Page 1 of 1

MQSeries.net Forum Index » WebSphere Message Broker (ACE) Support » Using an existing namespace for a new element in an XML msg
Jump to:  



You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
Protected by Anti-Spam ACP
 
 


Theme by Dustin Baccetti
Powered by phpBB © 2001, 2002 phpBB Group

Copyright © MQSeries.net. All rights reserved.