Функция документа XSLT возвращает пустой результат в Maven POM

Привет!

Я хочу извлечь некоторые свойства из разных POM Maven в XSLT через функцию документа. Сам сценарий работает нормально, но функция документа возвращает пустой результат для POM, если у меня есть xmlns="http://maven.apache.org/POM/4.0.0" в тег проекта. Если убрать, то все нормально.

Любая идея, как заставить это работать, оставив атрибут xmlns там, где он принадлежит, или почему это не работает с атрибутом на месте?

Вот соответствующая часть моего XSLT:

<xsl:template match="abcs">
 <xsl:variable name="artifactCoordinate" select="abc"/>
   <xsl:choose>
        <xsl:when test="document(concat($artifactCoordinate,'-pom.xml'))">
         <abc>
          <ID><xsl:value-of select="$artifactCoordinate"/></ID>
    <xsl:copy-of select="document(concat($artifactCoordinate,'-pom.xml'))/project/properties"/>
   </abc>
         </xsl:when>
            <xsl:otherwise>
       <xsl:message terminate="yes">
           Transformation failed: POM "<xsl:value-of select="concat($artifactCoordinate,'-pom.xml')"/>" doesn't exist. 
       </xsl:message>
      </xsl:otherwise> 

</xsl:choose> 

And, for completeness, a POM extract with the "bad" attribute:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ... -->
<properties>
    <proalpha.version>[5.2a]</proalpha.version>
    <proalpha.openedge.version>[10.1B]</proalpha.openedge.version>
    <proalpha.optimierer.version>[1.1]</proalpha.optimierer.version>
    <proalpha.sonic.version>[7.6.1]</proalpha.sonic.version>
</properties>
 </project>

person Jan    schedule 29.04.2010    source источник
comment
Хороший вопрос (+1). Смотрите мой ответ для объяснения проблемы и для наиболее часто используемого решения. :)   -  person Dimitre Novatchev    schedule 29.04.2010


Ответы (3)


Ваша проблема в том, что извлечение POM использует пространство имен по умолчанию. Это означает, что элементы, хотя и без префикса, находятся в "http://maven.apache.org/POM/4.0.0" -- не в "пространстве имен нет".

Однако в этом выражении XPath в коде XSLT:

document(concat($artifactCoordinate,'-pom.xml'))/project/properties

имена project и properties не имеют префикса. XPath всегда рассматривает имена без префикса как принадлежащие "нет пространства имен". Следовательно, такие элементы не найдены и ни один узел не выбран.

Решение. Добавьте определение пространства имен в свой <xsl:stylesheet>, скажем:

  xmlns:p="http://maven.apache.org/POM/4.0.0"

Затем перепишите имена элементов во всех выражениях, ссылающихся на узлы POM, с someElement на p:someElement. Например:

document(concat($artifactCoordinate,'-pom.xml'))/p:project/p:properties
person Dimitre Novatchev    schedule 29.04.2010
comment
Спасибо, Дмитрий, это работает! Прямо сейчас это решение дает мне xmlns:pom=... в каждом элементе, который я получаю из вызова функции документа, но я надеюсь найти способ избавиться от этого, возможно, предварительно предоставив объявление в целевом документе. - person Jan; 30.04.2010
comment
@Jan: Просто добавьте к <xsl:stylesheet> следующий атрибут: exclude-result-prefixes="pom" - person Dimitre Novatchev; 30.04.2010
comment
Ах! Это приятное дополнение - спасибо. Я также нашел общее решение, которое пригодится для моей особой потребности (см. мой ответ). - person Jan; 30.04.2010

Это проблема пространства имен. xmlns="http://maven.apache.org/POM/4.0.0" в исходном документе означает, что все элементы по умолчанию помещаются в "http://maven.apache.org/POM/4.0.0" в XML-документе.

Если вы хотите получить их в своем xslt, вам нужно объявить это пространство имен в вашем xslt (с префиксом или без него), а затем использовать это пространство имен при выборе ваших элементов.

Например, я предполагаю, что шаблон в вашем примере предназначен для соответствия элементу «abcs» в вашем POM, да? Попробуйте добавить объявление пространства имен в свой xsl:stylesheet, например:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:pom="http://maven.apache.org/POM/4.0.0" version="1.0">

Это говорит XSL: «Я хочу добавить 'pom' в качестве префикса, который идентифицирует 'http://maven.apache.org/POM/4.0.0 в этом документе».

Затем при выборе элементов или соответствующих шаблонов используйте этот префикс, например:

<xsl:template match="pom:abcs">

Или попробуйте без префиксов, объявив свою таблицу стилей с пространством имен POM по умолчанию, например:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns="http://maven.apache.org/POM/4.0.0" version="1.0">
person Matt Gibson    schedule 29.04.2010
comment
Благодарю вас! К сожалению, глобальный подход не работает для меня - видимо, потому, что у меня есть теги и из других пространств имен. Возможно, мой вопрос был недостаточно точным - abcs находятся в другом пространстве имен. Однако для меня работает подход с префиксом, как предложил Димитре ниже. - person Jan; 30.04.2010
comment
@Matt: если вам нужно пространство имен по умолчанию при выборе элементов с помощью XPath, вам нужно использовать xpath-default-namespace (поддерживается в XSLT 2.0 или более поздних версиях), как описано в w3.org/TR/xslt20/#unprefixed-qnames. Установка пространства имен по умолчанию с помощью xmlns="..." настраивает только пространство имен по умолчанию для литералов XML в таблице стилей, выражения XPath не затрагиваются. - person markusk; 02.05.2010
comment
@markusk Спасибо за разъяснение; Я еще не использовал пространство имен xpath-default-name, уверен, что когда-нибудь оно мне пригодится! - person Matt Gibson; 05.05.2010

Node (при использовании XSLT 2.0+) также может быть адресован через *, потому что они находятся в другом пространстве имен.

    <xsl:copy-of select="document(concat($artifactCoordinate,'-pom.xml'))/*:project/*:properties)"/> 

Это может быть просто удобно или особенно полезно, если пространство имен неизвестно. В этом случае приятным побочным эффектом является то, что если пространство имен помечено таким образом, узлы из другого пространства имен не получают аннотации, что в нашем случае нежелательно.

person Jan    schedule 30.04.2010
comment
@Jan: синтаксис *:name поддерживается только в XPath 2.0. - person Dimitre Novatchev; 30.04.2010
comment
@Jan: Также обратите внимание, что вы можете использовать xpath-default-namespace, если используете XSLT 2.0 или более позднюю версию, как описано в w3.org/TR/xslt20/#unprefixed-qnames. - person markusk; 02.05.2010
comment
@Dimitre: Конечно, извините, я забыл добавить эту деталь (используя это). - person Jan; 04.06.2010