xml - XSLT 2.0 - filter nodes by lang/locale hierarchy and content -
xml - XSLT 2.0 - filter nodes by lang/locale hierarchy and content -
using xslt 2.0, how can dynamically process xml document remove nodes have xml:lang attribute, based on rules/requirements below?
requirements:
find node (and it's same-type immediate siblings) attributexml:lang know xml:lang values have 3-tier hierarchy based on language/locale, non-exhaustive examples below: x-default (tier 1, highest) en (tier 2, language prefix, other value examples: fr, es, ru) en-us (tier 3, language prefix followed suffix, other value examples: en-gb, en-ca) based on known hierarchy, duplicate values should removed. when removing duplicates, take consideration existence of additional attributes sibling may have. leave rest of xml document unmolested example dataset:
<?xml version="1.0" encoding="utf-8"?> <arbitrarydepth> <scenario1 xml:lang="x-default">a default node value</scenario1> <scenario1 xml:lang="en">a default node value</scenario1> <scenario1 xml:lang="en-us">a default node value</scenario1> <scenario2 xml:lang="x-default">the orig value</scenario2> <scenario2 xml:lang="en">the orig value</scenario2> <scenario2 xml:lang="en-us">a new value</scenario2> <scenario3 xml:lang="x-default">the orig value</scenario3> <scenario3 xml:lang="en">a new value</scenario3> <scenario3 xml:lang="en-us">the orig value</scenario3> <scenario4 xml:lang="x-default">the orig value</scenario4> <scenario4 xml:lang="en">an english language value</scenario4> <scenario4 xml:lang="en-us">an english language value</scenario4> <scenario4 xml:lang="fr">a french value</scenario4> <scenario4 xml:lang="fr-fr">a french value</scenario4> <scenario4 xml:lang="fr-ca">a french canada value</scenario4> <scenario5 xml:lang="x-default" attr0="something here">the orig value</scenario5> <scenario5 xml:lang="en" attr1="some attribute">the orig value</scenario5> <scenario5 xml:lang="en-us" attr2="some other attribute">the orig value</scenario5> <scenario5 xml:lang="fr" attr0="something here">the orig value</scenario5> <scenario5 xml:lang="fr-fr">the orig value</scenario5> </arbitrarydepth> example resultset:
<?xml version="1.0" encoding="utf-8"?> <arbitrarydepth> <scenario1 xml:lang="x-default">a default node value</scenario1> <scenario2 xml:lang="x-default">the orig value</scenario2> <scenario2 xml:lang="en-us">a new value</scenario2> <scenario3 xml:lang="x-default">the orig value</scenario3> <scenario3 xml:lang="en">a new value</scenario3> <scenario3 xml:lang="en-us">the orig value</scenario3> <scenario4 xml:lang="x-default">the orig value</scenario4> <scenario4 xml:lang="en">an english language value</scenario4> <scenario4 xml:lang="en-us">an english language value</scenario4> <scenario4 xml:lang="fr">a french value</scenario4> <scenario4 xml:lang="fr-ca">a french canada value</scenario4> <scenario5 xml:lang="x-default" attr0="something here">the orig value</scenario5> <scenario5 xml:lang="en" attr1="some attribute">the orig value</scenario5> <scenario5 xml:lang="en-us" attr2="some other attribute">the orig value</scenario5> </arbitrarydepth>
this should fulfill requirements, except lastly 1 matching dynamic attributes:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:template match="*"> <xsl:variable name="elementname" select="name()"/> <xsl:variable name="contenttext" select="normalize-space(.)"/> <xsl:choose> <xsl:when test="not(@xml:lang)"> <!-- non-lang element --> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates select="*"/> </xsl:copy> </xsl:when> <xsl:when test="@xml:lang='x-default'"> <!-- tier 1: xml:lang="x-default" --> <xsl:copy-of select="."/> </xsl:when> <xsl:when test="contains(@xml:lang,'-')"> <!-- tier 3: xml:lang="en-us" --> <xsl:variable name="baselang" select="substring-before(@xml:lang, '-')"/> <xsl:choose> <xsl:when test="../*[name()=$elementname][@xml:lang=$baselang][normalize-space(.)=$contenttext]"> <!-- same text tier 2 parent --> </xsl:when> <xsl:when test="../*[name()=$elementname][@xml:lang=$baselang]"> <xsl:copy-of select="."/> </xsl:when> <xsl:when test="../*[name()=$elementname][@xml:lang='x-default'][normalize-space(.)=$contenttext]"> <!-- same text tier 1 parent --> </xsl:when> <xsl:when test="../*[name()=$elementname][@xml:lang='x-default']"> <xsl:copy-of select="."/> </xsl:when> <xsl:otherwise> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <!-- tier 2: xml:lang="en" --> <xsl:choose> <xsl:when test="../*[name()=$elementname][@xml:lang='x-default'][normalize-space(.)=$contenttext]"> <!-- same text tier 1 parent --> </xsl:when> <xsl:when test="../*[name()=$elementname][@xml:lang='x-default']"> <xsl:copy-of select="."/> </xsl:when> <xsl:otherwise> <!-- no matching parent --> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> demo: http://www.xsltcake.com/slices/uopn40
matching dynamic attributes between parent , kid complex. have loop trough attributes , compare against current parent. if attribute missing on parent, or if it's value different, have maintain new element.
to fulfill lastly requirement, think have move imperative language (c#, javascript, java).
xml xslt xpath xslt-2.0
Comments
Post a Comment