|
RSS Feed - WebSphere MQ Support
|
RSS Feed - Message Broker Support
|
 |
|
Using an existing namespace for a new element in an XML msg |
« View previous topic :: View next topic » |
Author |
Message
|
simonalexander2005 |
Posted: Wed Mar 10, 2021 7:16 am Post subject: Using an existing namespace for a new element in an XML msg |
|
|
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 |
|
 |
timber |
Posted: Wed Mar 10, 2021 5:29 pm Post subject: |
|
|
 Grand Master
Joined: 25 Aug 2015 Posts: 1292
|
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 |
|
 |
simonalexander2005 |
Posted: Thu Mar 11, 2021 2:23 am Post subject: |
|
|
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 |
|
 |
simonalexander2005 |
Posted: Thu Mar 11, 2021 2:47 am Post subject: |
|
|
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 |
|
 |
timber |
Posted: Thu Mar 11, 2021 11:55 am Post subject: |
|
|
 Grand Master
Joined: 25 Aug 2015 Posts: 1292
|
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 |
|
 |
simonalexander2005 |
Posted: Fri Mar 12, 2021 2:47 am Post subject: |
|
|
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 |
|
 |
timber |
Posted: Fri Mar 12, 2021 3:28 am Post subject: |
|
|
 Grand Master
Joined: 25 Aug 2015 Posts: 1292
|
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 |
|
 |
|
|
 |
|
Page 1 of 1 |
|
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
|
|
|
|