Enforcing attribute value uniqueness within a given tag, not necessarily across the whole file - xsd

I'd like to validate an XML file against XSD 1.0 and require the values of one attribute to be unique within that one element, but allowing duplicates in different tags.
For exemple, I'd like the attribute (det) not to contain repetitions within each <Client> tag, but I'd like to allow the attribute to have duplicates in different clients.
So, I'd like to have the snipped below to be valid...
<Client id="1">
<RiscSoc det="01" av="01"/>
<RiscSoc det="02" av="02"/>
<RiscSoc det="99" av="02"/>
</Client>
<Client id="2">
<RiscSoc det="01" av="01"/>
<RiscSoc det="02" av="02"/>
<RiscSoc det="99" av="02"/>
</Client>
... but not this one below:
<Client id="1">
<RiscSoc det="01" av="01"/>
<RiscSoc det="01" av="02"/>
</Client>
Can that be done with XSD 1.0 (which is the version used in the software I have available)? How?
I've done considerable searching but I can only find examples of unique and primary keys to enforce uniqueness across the whole XML file.
Thanks!!

Related

Filtering XML via XMLFilter in Excel, but wrong XPath

I have an XML from which I want to filter the Title and EMail.
This is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xml:base="https://mysite/vis/_api/">
<id>https://mysite/vis/_api/Web/GetUserById(1284)</id>
<category term="SP.User" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/GetUserById(1284)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Groups" type="application/atom+xml;type=feed" title="Groups" href="Web/GetUserById(1284)/Groups" />
<title />
<updated>2020-01-15T18:23:48Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:Id m:type="Edm.Int32">1284</d:Id>
<d:IsHiddenInUI m:type="Edm.Boolean">false</d:IsHiddenInUI>
<d:LoginName>i:0#.w|opmain\xespsa</d:LoginName>
<d:Title>Alex, Johnson</d:Title>
<d:PrincipalType m:type="Edm.Int32">1</d:PrincipalType>
<d:Email>Alex.Johnson#stackoverflow.net</d:Email>
<d:IsSiteAdmin m:type="Edm.Boolean">false</d:IsSiteAdmin>
<d:UserId m:type="SP.UserIdInfo">
<d:NameId>s-1-5-21-1377870913-3677095212-3270174719-20443</d:NameId>
<d:NameIdIssuer>urn:office:idp:activedirectory</d:NameIdIssuer>
</d:UserId>
</m:properties>
</content>
</entry>
I tried using the XMLFILTER function from Excel, but my XPath is wrong:
=XMLFILTERN(E4;"//content/title[1]")
How can I get the correct xpath in this case since Title is inside content?
TLDR/from comments: Excel doesn't care about namespaces. Reuse the prefixes in the source XML and ignore the default namespace...
//content/m:properties/d:Title
It's probably because your XML has namespaces.
content is in the default namespace http://www.w3.org/2005/Atom.
properties is in the namespace http://schemas.microsoft.com/ado/2007/08/dataservices/metadata bound to the prefix m.
Title is in the namespace http://schemas.microsoft.com/ado/2007/08/dataservices bound to the prefix d.
I'm not sure how Excel/XMLFILTER handles namespaces in XPath (hopefully someone answers that does), but ideally you'd bind those namespace uris to prefixes and use the prefixes in the XPath.
If you can't, you'll probably have to resort to using local-name()...
//*[local-name()='content']/*[local-name()='properties']/*[local-name()='Title']
If there's a possibility of elements with the same local name, but different namespaces (and you need to distinguish between them), you can also use namespace-uri()...
//*[local-name()='content' and namespace-uri()='http://www.w3.org/2005/Atom']/*[local-name()='properties' and namespace-uri()='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata']/*[local-name()='Title' and namespace-uri()='http://schemas.microsoft.com/ado/2007/08/dataservices']
Of course this is all assuming that those two XPath 1.0 functions are supported.
For the xPath argument in Excel, you should use the namespace:
The full path:
//content/m:properties/d:Title
//content/m:properties/d:Email
In your particular instance, you can more simply use:
//d:Title
//d:Email

Repeating node multiple times based on the input structure

I have one requirement, I am new to XSLT language so I am looking for your help for my below requirement.
Below is the input xml payload
<?xml version="1.0" encoding="UTF-8" ?>
<ns0:sendfile xmlns:ns0="namepsace here">
<Delivery>
<IssueDateTime>2016-05-24T09:25:19z</IssueDateTime>
<Item>
<order>
<orderChar>
<orderName />
<orderVal />
</orderChar>
<orderInfo>
<Product />
<Batch />
<Qty />
<UOM />
</orderInfo>
</order>
</Item>
</Delivery>
so in the file orderchar node and orderInfo node will repeat multiple times based on that in receiver structure 2 nodes should repeat. for example
orderchar segment is repeating 20 times, in receiver also E1ADRM segment should repeat same number of times.
order info also same case in receiver E1DRM segment should repeat same number of times.In case any of the node will not come in receiver also the segment should not populate.
I think we can do this some value of select with that syntax. could you please help me on this.
I tried with below code and able to generate the node. but when repeated nodes are coming the repeated receiver nodes are not populating.
<ns0:if test="count(./order/orderChar)!=0">
<E1EDL12 SEGMENT="1">
<ATNAM>
<ns0:value-of select="./orderChar/orderName"/>
</ATNAM>
<ATWRT>
<ns0:value-of select="./orderChar/orderName"/>
</ATWRT>
</E1EDL12>
above code tried for only for one segment.could you please suggest what modification I have to do to populate multiple times.
Regards,
Janardhan
You really haven't made your requirement very clear, but my guess would be that you want something like:
<xsl:for-each select="orderChar">
<ATNAM>
<xsl:value-of select="orderName"/>
</ATNAM>
<ATWRT>
<xsl:value-of select="./orderChar/orderName"/>
</ATWRT>
</xsl:for-each>

XML Schema: Ignore tags with foreign namespace

Say I have the following xml document:
<root xmlns:p="uri:myNamespace">
<p:tagA>
<p:tagB />
</p:tagA>
</root>
The tagB must only be inside a tagA. I can write an xsd that validates that:
<xsd:schema ... targetNamespace="uri:myNamespace" elementFormDefault="qualified">
<xsd:element name="tagA">
<xsd:complexType>
<xsd:element name="tagB" type="..." />
</xsd:complexType>
</xsd:element>
</xsd:schema>
Now here comes the problem: I want to ignore any tags in between of foreign namespace:
<root xmlns:p="uri:myNamespace">
<p:tagA>
<whatever />
<foo>
<bar>
<p:tagB />
</bar>
</foo>
</p:tagA>
</root>
As you can see tagB is now nested within other tags without namespace.
Is it possible (how?) to write an XSD that still enforces that the only tag within tagA from my namespace is a tagB but there may be any tags of other namespaces inbetween?
The content models used in XSD (and DTDs, and Relax NG) to constrain the content of an element define legal sequences of children; they work like a single production rule in a context-free grammar. It's possible to constrain descendants at deeper levels, but it requires an unbroken chain of declarations: in your example you need declarations for foo and bar when they appear within a p:tagA element, to ensure that between them they contain exactly one p:tagB element. But your starting point is that you don't want to constrain those elements.
So: you cannot use content models to express the constraint you have in mind.
In XSD 1.1, you can use an assertion attached to the p:tagA element to require that it contain exactly on p:tagB element among its descendants (count(.//p:tagB) eq 1). You cannot, however, use an assertion attached to p:tagB to require that it appear only in p:tagA elements: assertions can look down, but not up, in the tree. (If you know the name of a container guaranteed to be present, you can use an assertion on that container that asserts that every p:tagB element is contained by a p:tagA element, using an assertion like count(.//p:tagA//p:tagB) eq count(.//p:tagB).)
XSD 1.1 is currently supported by some but not all XSD validators.

How to prevent self-referencing foreign key values in XSD schema?

My XML (simplified) is like this:
<Actions>
<Action Id="1">
</Action>
<Action Id="2">
<DoSomething>
<ActionRef ActionId="1" /> <!-- valid -->
</DoSomething>
</Action>
</Actions>
The ActionId attribute value references the Id attribute value of the Action element. I've already set up a foreign key constraint in the XSD, and it works correctly.
I want to prevent self-referencing values in the foreign field, like this:
<Actions>
<Action Id="1">
</Action>
<Action Id="2">
<DoSomething>
<ActionRef ActionId="2" /> <!-- invalid -->
</DoSomething>
</Action>
</Actions>
Of course, this can easily be done within the application that processes the XML, and I'll fall back on that if what I'm asking for isn't possible, but I'd much rather have this done automatically by the validation process.
I tried adding [not(#ActionId = ../#Id)] to the foreign key selector XPath query, but that isn't valid in that context (nor am I sure it's correct either). Other than that, I have no idea what else to try, and it doesn't look like many people on the internets even set up foreign key relationships in their XSDs, let alone prevent this kind of situation (I found nothing on this exact topic).
It cannot be done - the selector syntax for XSD constraints is very limited. Other alternatives may include Schematron, which should be reasonable to integrate assuming your runtime has access to an XSLT processor. The effort could pay off is you decide to add more validation rules separate from the code of the application that processes the XML.

XSD for XML with all unique node names

My XML file looks something like this:
<Fields>
<Humanities>
<Performing_Arts>
<Dance />
<Music />
</Performing_Arts>
<Visual_Arts>
<Painting />
<Sculptue />
</Visual_Arts>
</Humanities>
<Social_Sciences>
<Psychology>
<Cultural_Psychology />
<Social_Psychology />
</Psychology>
</Social_Sciences>
</Fields>
I want to write an XML Schema, for this file, so that no two nodes, irrespective of location in the file can have duplicate names.
Any node in this file should be allowed to have unlimited child nodes, to any sub-level.
How might I achieve this goal?
skaffman is quite right, you needto enclose your values as either attributes or elements, if you are unsure, w3 schools hasa great tutorial on this;
http://www.w3schools.com/xml/xml_elements.asp
http://www.w3schools.com/xml/xml_attributes.asp
An example of a possible xml representation of your data might be:
<fields>
<department name="Humanities">
<subject name="Peforming Arts">
<topic name="Dance"/>
<topic name="Music"/>
</subject>
<subject name="Visual Arts">
<topic name="Painting"/>
<topic name="Sculpture"/>
</subject>
</department>
<department name="Social Sciences">
<subject name="Psychology">
<topic name="Cultural Psychology"/>
<topic name="Social Psychology"/>
</subject>
</department>
</fields>
Notes:
You can see that this is roughly equivalent to a database with three tables: department, subject and topic, with FK relationships between the parent and children. This is really what XML encapsulates, but in text form, and is the sort of thing to bear in mind while you design your layout.
I've used all lower-case names for elements and attributes. This is a personal thing as xsl/xpath as case sensitive, so making everything lowercase avoids the opporyunity for horrid bugs later

Resources