XSLT XPATH : в коллекции файлов XHTML для данного XHTML: измените содержимое заголовка узла на имя файла XHTML

#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, например, any match="h:title" become match="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" , но это было в вашем исходном коде.