Я хочу сопоставить корневой элемент «FOO» и выполнить преобразование (добавить атрибут версии), оставив все остальное как есть.Преобразование, которое я имею до сих пор, выглядит следующим образом:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://schemas.foo.com/fooNameSpace"> <xsl:template match="//FOO"> <xsl:choose> <xsl:when test="@version"> <xsl:apply-templates select="node()|@*" /> </xsl:when> <xsl:otherwise> <FOO> <xsl:attribute name="version">1</xsl:attribute> <xsl:apply-templates select="node()|@*" /> </FOO> </xsl:otherwise> </xsl:choose> </xsl:template>
Однако это не выполняет никакого преобразования.Он даже не обнаруживает элемент.Поэтому мне нужно добавить пространство имен, чтобы оно заработало:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fd="http://schemas.foo.com/fooNameSpace"> <xsl:template match="//fd:FOO"> …
Но это присоединяет атрибут пространства имен к элементу FOO, а также к другим элементам:
<FOO xmlns:fd="http://schemas.foo.com/fooNameSpace" version="1" id="fooid"> <BAR xmlns="http://schemas.foo.com/fooNameSpace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
Вот исходный XML:
<?xml version="1.0" encoding="UTF-8"?> <FOO xmlns="http://schemas.foo.com/fooNameSpace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <BAR> <Attribute name="HEIGHT">2067</Attribute> </BAR> </FOO>
Вы можете указать пространство имен по умолчанию для выражений XPath, добавив атрибут xpath-default-namespace, как описано в разделе 5.2 Непрефиксные QNames в выражениях и шаблонах стандарта XSLT 2.0.
xpath-default-namespace
Пример:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://schemas.foo.com/fooNameSpace"> <xsl:template match="FOO[not(@version)]"> <xsl:copy> <xsl:attribute name="version">1</xsl:attribute> <xsl:apply-templates select="node()|@*" /> </xsl:copy> </xsl:template> <!-- Identity template for copying everything else --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*" /> </xsl:copy> </xsl:template> </xsl:stylesheet>
Вот одно решение в духе XSLT :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fd="http://schemas.foo.com/fooNameSpace" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*" name="identity"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="/*[self::fd:FOO and not(@version)]"> <xsl:copy> <xsl:attribute name="version">1</xsl:attribute> <xsl:call-template name="identity"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Когда это преобразование применяется к предоставленному XML-документу, получается нужный, правильный результат :
<FOO xmlns="http://schemas.foo.com/fooNameSpace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1"> <FOO> <BAR> <Attribute name="HEIGHT">2067</Attribute> </BAR> </FOO> </FOO>
Это работает для меня, используя xsltproc / libxslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://schemas.foo.com/fooNameSpace"> <xsl:template match="/ns:FOO"> <xsl:copy> <xsl:if test="not(@version)"> <xsl:attribute name="version">1</xsl:attribute> </xsl:if> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template> <xsl:template match="node() | @*"> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Производит:
<?xml version="1.0"?> <FOO xmlns="http://schemas.foo.com/fooNameSpace" version="1"> <BAR> <Attribute>2067</Attribute> </BAR> </FOO>