XSLT: Removing Synonymous Namespaces

I have a large collection of XML files that I need to convert using XSLT. The problem is that many of these files were written by different people, and they do not use consistent names to refer to schemes. For example, one file may use:

xmlns:itemType="http://example.com/ItemType/XSD"

where another may use the prefix "it" instead of "itemType":

xmlns:it="http://example.com/ItemType/XSD"

If this is not the case, a few files that use one or more synonyms for the same one are enough!

  <? xml version = "1.0"?>
 <Document
     xmlns: it = "http://example.com/ItemType/XSD"
     xmlns: itemType = "http://example.com/ItemType/XSD"
     xmlns: ItemType = "http://example.com/ItemType/XSD"
     ...

(obviously there was a lot of cutting and pasting)

Now, since pattern matching in the XSLT file works on the namespace prefix (as opposed to the schema to which this refers), the pattern matches only one of the options. Therefore, if I write something like:

  <xsl: template match = "SomeNode [@xsi: type = 'itemType: SomeType']">
         ...
     </ xsl: template>

Then it matches only a subset of the cases in which I want.

Question 1: Is there a way to get XSLT to fit all options?

Question 2: Is there a way to remove duplicates so that all output files use sequential naming?

I naively tried to use "namespace-alias", but I think I misunderstood what it does, because I can’t get it to do anything β€” either match all the options or affect the XML output.

  <? xsl: stylesheet
     version = "1.0"
     ...
     xmlns: it = "http://example.com/ItemType/XSD"
     xmlns: itemType = "http://example.com/ItemType/XSD"
     xmlns: ItemType = "http://example.com/ItemType/XSD"
     ...

     <xsl: output method = "xml" indent = "yes" />
     <xsl: namespace-alias stylesheet-prefix = "it" result-prefix = "ItemType" />
     <xsl: namespace-alias stylesheet-prefix = "itemType" result-prefix = "ItemType" />
+4
source share
2 answers

Attribute values ​​or text nodes will not be passed to QName unless you specify it explicitly. Although this is only possible in XSLT / XPath 2.0

In XSLT / XPath 1.0, you must do this "manually":

 <xsl:template match="SomeNode"> <xsl:variable name="vPrefix" select="substring-before(@xsi:type,':')"/> <xsl:variable name="vNCName" select="translate(substring-after(@xsi:type,$vPrefix),':','')"/> <xsl:if test="namespace::*[ name()=$vPrefix ] = 'http://example.com/ItemType/XSD' and $vNCName = 'SomeType'"> <!-- Content Template --> <xsl:if> </xsl:template> 

Edit: All in one template (less readable, possibly):

 <xsl:template match="SomeNode[ namespace::*[ name()=substring-before(../@xsi:type,':') ] = 'http://example.com/ItemType/XSD' and substring( concat(':',@xsi:type), string-length(@xsi:type) - 7 ) = ':SomeType' ]"> <!-- Content Template --> </xsl:template> 
+1
source

In XSLT 2.0 (regardless of whether you use schema understanding) you can write the predicate as [@xsi:type=xs:QName('it:SomeType')] , where "it" is the prefix declared in the stylesheet for this namespaces. It should not be the same as the prefix used in the source document.

Of course, matching element and attribute names (as opposed to content containing a QName) uses namespace URIs rather than prefixes in both XSLT 1.0 and XSLT 2.0.

+1
source

Source: https://habr.com/ru/post/1343827/


All Articles