2015-10-22 4 views
0

Нам нужно сделать несколько XML-документов, каждый из которых содержит один элемент информации из единого документа XML с неизвестным количеством элементов информации. Например, этот документ:Преобразование многоразветвленного XML-документа в несколько XML-документов

<alert> 
    <identifier>2.49.0.1.124.76fea972.2015</identifier> 
    <info> 
    <language>en</language> 
    </info> 
    <info> 
    <language>fr</language> 
    </info> 
</alert> 

должны давать эти два документа:

<alert> 
    <identifier>2.49.0.1.124.76fea972.2015</identifier> 
    <info> 
    <language>en</language> 
    </info> 
</alert> 

<alert> 
    <identifier>2.49.0.1.124.76fea972.2015</identifier> 
    <info> 
    <language>fr</language> 
    </info> 
</alert> 

Хотя обрезке братьев и сестер элемента «информация», нам нужно скопировать все узлы, атрибуты, пространства имен и т.д. всего предков (от корня), а также всех узлов, атрибутов, пространств имен и т. д. конкретного элемента информации.

Я новичок в XSLT и не понимаю, как это сделать. Любая помощь будет принята с благодарностью!

+2

Можете ли вы хотя бы использовать процессор XSLT 2.0, например Saxon 9? Процессоры XSLT 1.0 не поддерживают создание нескольких файлов результатов с одним преобразованием, если не поддерживается некоторым элементом расширения. –

+0

Да, решение XSLT 2.0 было бы хорошо. –

ответ

0

Используя процессор XSLT 2.0, как Saxon 9 или AltovaXML или XmlPrime вы можете использовать подход, как это:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

<xsl:template match="@* | node()"> 
    <xsl:copy> 
    <xsl:apply-templates select="@* , node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:apply-templates select="alert/info" mode="split"/> 
</xsl:template> 

<xsl:template match="info" mode="split"> 
    <xsl:result-document href="language-{language}.xml"> 
    <xsl:apply-templates select="/*"> 
     <xsl:with-param name="info" select="current()" tunnel="yes"/> 
    </xsl:apply-templates> 
    </xsl:result-document> 
</xsl:template> 

<xsl:template match="info"> 
    <xsl:param name="info" tunnel="yes"/> 
    <xsl:if test=". is $info"> 
    <xsl:next-match/> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

Если вход в определенном пространстве имен, а затем использовать, например, <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="urn:oasis:names:tc:emergency:cap:1.2">.

Если вы хотите запустить XSLT независимо от пространства имен, а затем использовать

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

<xsl:template match="@* | node()"> 
    <xsl:copy> 
    <xsl:apply-templates select="@* , node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:apply-templates select="*:alert/*:info" mode="split"/> 
</xsl:template> 

<xsl:template match="*:info" mode="split"> 
    <xsl:result-document href="language-{language}.xml"> 
    <xsl:apply-templates select="/*"> 
     <xsl:with-param name="info" select="current()" tunnel="yes"/> 
    </xsl:apply-templates> 
    </xsl:result-document> 
</xsl:template> 

<xsl:template match="*:info"> 
    <xsl:param name="info" tunnel="yes"/> 
    <xsl:if test=". is $info"> 
    <xsl:next-match/> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 
+0

Это очень близко. Однако в самом деле корневой элемент всегда имеет пространство имен, например (также может быть префикс пространства имен). Можно ли сделать преобразование пространства имен чувствительным? (например, вместо select = "alert/info" use select = "/ * [local-name() = 'alert']/* [local-name() = 'info']"> и т. Д .. –

+0

Изменилось ли это пространство имен? Если нет, я бы просто использовал ' '. –

+0

@EliotChristian, я отредактировал ответ, чтобы показать, как работать с одним пространством имен или как писать таблицу стилей для обработки любого пространства имен. –

1

Легко в xsh:

my $orig := open file.xml ; 
for my $info in /alert/info { 
    my $clone := clone $orig ; 
    my $i = count($info/preceding::info) ; 
    delete $clone/alert/info[count(preceding::info) = $i] ; 
    save :f concat('file', $i, '.xml') $clone ; 
} 
+0

Эй, эта библиотека оболочек выглядит очень интересно! Спасибо. – potame

0

Или, возможно, это немного проще, чем решение Мартина:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

<xsl:template match="/"> 
<xsl:for-each select="alert/info"> 
    <xsl:result-document href="language-{language}.xml"> 
    <alert> 
     <xsl:copy-of select="../identifier"/> 
     <xsl:copy-of select="."/> 
    </alert> 
    </xsl:result-document> 
</xsl:for-each> 
</xsl:template> 

</xsl:stylesheet> 
+0

Спасибо за это предложение, но обобщенное решение Мартина необходимо, потому что фактические предупреждения CAP намного больше переменные и сложные (данные в реальном времени можно увидеть в https: // a lerts.internetalerts.org/feed) –

 Смежные вопросы

  • Нет связанных вопросов^_^