Приветствия!

Я хочу извлечь некоторые свойства из разных Maven POM в 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> 

И, для полноты, извлечение POM с атрибутом "bad":

<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>
6
Jan 29 Апр 2010 в 11:46
Хороший вопрос (+1). См. В моем ответе объяснение проблемы и наиболее часто используемое решение. :)
 – 
Dimitre Novatchev
29 Апр 2010 в 16:58

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
11
Dimitre Novatchev 29 Апр 2010 в 16:56
Спасибо, Димитр - это работает! Прямо сейчас это решение дает мне xmlns: pom = "..." в каждом элементе, который я получаю из вызова функции документа, но я надеюсь найти способ избавиться от этого, возможно, предоставив ранее объявление в целевом документе.
 – 
Jan
30 Апр 2010 в 13:48
@Jan: просто добавьте к <xsl:stylesheet> следующий атрибут: exclude-result-prefixes="pom"
 – 
Dimitre Novatchev
30 Апр 2010 в 16:53
Ах! Хорошее дополнение - спасибо. Я также нашел общее решение, которое пригодится для моих особых нужд (см. Мой ответ).
 – 
Jan
30 Апр 2010 в 18:22

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

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

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

<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">
3
Matt Gibson 29 Апр 2010 в 16:46
Спасибо! К сожалению, «глобальный подход» у меня не работает - видимо, потому, что у меня есть теги и из других пространств имен. Возможно, мой вопрос был недостаточно точным - abcs находятся в другом пространстве имен. Однако подход по префиксу работает для меня, как, например, Димитр, предложенный ниже.
 – 
Jan
30 Апр 2010 в 13:45
@Matt: если вы хотите использовать пространство имен по умолчанию при выборе элементов с помощью XPath, вам необходимо использовать xpath-default-namespace (поддерживается в XSLT 2.0 или новее), как описано в w3.org/TR/xslt20/#unprefixed-qnames. Установка пространства имен по умолчанию с помощью xmlns="..." только настраивает пространство имен по умолчанию для литералов XML в таблице стилей, выражения XPath не затрагиваются.
 – 
markusk
2 Май 2010 в 09:09
Спасибо за разъяснения; Я еще не использовал пространство имен xpath-default-name, уверен, что когда-нибудь это пригодится мне в будущем!
 – 
Matt Gibson
5 Май 2010 в 12:54

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

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

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

1
Jan 20 Фев 2013 в 13:09
1
@Jan: синтаксис *:name поддерживается только в XPath 2.0.
 – 
Dimitre Novatchev
30 Апр 2010 в 19:59
@Jan: Также обратите внимание, что вы можете использовать xpath-default-namespace, если используете XSLT 2.0 или новее, как описано в w3.org/TR/xslt20/#unprefixed-qnames.
 – 
markusk
2 Май 2010 в 09:12
@Dimitre: Конечно - извините, я забыл добавить эту деталь (используя это).
 – 
Jan
4 Июн 2010 в 16:30