#xslt #xpath
#xslt #xpath
Вопрос:
Я получил кучу файлов dummy*.xhtml с заголовочным узлом, содержащим: title XHTML
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style xmlns:xhtml="http://www.w3.org/1999/xhtml" type="text/css" xml:space="preserve"/>
<meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
<title>title XHTML</title>
</head>
<body>
<p>Dummy</p>
</body>
</html>
Для каждого файла мне нужно заменить содержимое заголовка узла на его имя файла.
Если файл является dummy.xhtml, содержимое заголовка узла должно стать: dummy.xhtml
Я попробовал следующий XSLT :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="h">
<xsl:output method="xhtml" version="1.0" encoding="UTF-8" indent="yes" standalone="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="h:title">
<title>
<!-- <xsl:value-of select="$xhtml_name"/> -->
</title>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="collection('?select=dummy*.xhtml')">
<xsl:variable name="xhtml_name">
<xsl:value-of select="tokenize(base-uri(), '/')[last()]"/>
</xsl:variable>
<xsl:message>xhtml_name : <xsl:value-of select="$xhtml_name"/></xsl:message>
<xsl:variable name="path_to_cleaned">
<xsl:value-of select="iri-to-uri(replace(document-uri(current()), '.xhtml', '.cleaned.xhtml'))"/>
</xsl:variable>
<xsl:message>path_to_cleaned : <xsl:value-of select="$path_to_cleaned"/></xsl:message>
<xsl:result-document indent="yes" method="xhtml" href="{$path_to_cleaned}">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Но я попал в ловушку, потому что переменная $xhtml_name является локальной для : template match=»/».
Затем с сомнением я попытался определить переменную $xhtml_name и вставить в нее коллекцию, чтобы сделать ее глобальной.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="h">
<xsl:output method="xhtml" version="1.0" encoding="UTF-8" indent="yes" standalone="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="h:title">
<title>
<xsl:value-of select="$xhtml_name"/>
</title>
</xsl:template>
<xsl:variable name="xhtml_name">
<xsl:for-each select="collection('?select=dummy*.xhtml')">
<xsl:value-of select="tokenize(base-uri(), '/')[last()]"/>
<xsl:variable name="path_to_cleaned">
<xsl:value-of select="iri-to-uri(replace(document-uri(current()), '.xhtml', '.cleaned.xhtml'))"/>
</xsl:variable>
<xsl:message>path_to_cleaned : <xsl:value-of select="$path_to_cleaned"/></xsl:message>
<xsl:result-document indent="yes" method="xhtml" href="{$path_to_cleaned}">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:for-each>
</xsl:variable>
</xsl:stylesheet>
Как и ожидалось, он не работает и возвращает ошибки.
Как этого добиться?
Спасибо за помощь.
Ответ №1:
Я бы использовал параметр туннеля, например
<xsl:template match="h:title">
<xsl:param name="xhtml_name" tunnel="yes"/>
<title>
<xsl:value-of select="$xhtml_name"/>
</title>
</xsl:template>
вы проходите дальше в своем первом образце в строке
<xsl:result-document indent="yes" method="xhtml" href="{$path_to_cleaned}">
<xsl:apply-templates>
<xsl:with-param name="xhtml_name" tunnel="yes" select="$xhtml_name"/>
</xsl:apply-templates>
</xsl:result-document>
Обратите внимание , что несколько строк в вашем XSLT можно упростить и сократить , используя xpath-default-namespace
и используя <xsl:variable name="foo" select="expression"/>
вместо <xsl:variable name="foo"><xsl:value-of select="expression"/></xsl:variable>
.
Комментарии:
1. Большое спасибо, Мартин, все в порядке. В мое обучение добавлена новая функция. Вы подходите для определения переменной, она легче, поэтому лучше. Что касается xpath-default-namespace, я действительно новичок в этой области. Будет ли ваше предложение удалять xmlns:fn=» w3.org/2005/xpath-functions » из <title xmlns:fn=» dummy.xhtml w3.org/2005/xpath-functions «>dummy.xhtml</title > который появляется в очищенном файле?
2. @Bin31, если вы имеете дело с элементами XHTML для всех или большинства шаблонов и выборок XPath, их короче и проще объявлять
<xsl:stylesheet xpath-default-namespace="http://www.w3.org/1999/xhtml" ...>
заранее, так как тогда вам не нужен префикс для сопоставления и выбора элементов XHTML, например, anymatch="h:title"
becomematch="title"
.3. Итак, в основном: <xsl:таблица стилей xpath-default-namespace=» w3.org/1999/xhtml » версия=»2.0″ xmlns:xsl=» w3.org/1999/XSL/Transform » > этого достаточно, верно?
4. Я заметил, что в <title xmlns=»»>00000286.0002001_css.cleaned.xhtml</title> осталось немного xmlns=»», может быть, я был не совсем прав в своем посте выше.
5. Для выбора и сопоставления вам нужно только
xpath-default-namespace
, чтобы создать новые результирующие элементы XHTML, которые вам также нужно будет объявитьxmlns="http://www.w3.org/1999/xhtml"
, но это было в вашем исходном коде.