XSLT: замена узла эквивалентным узлом другого документа
Я хочу заменить некоторые узлы XML-файла эквивалентными узлами другого XML-файла. Поскольку это не будет достаточно сложной задачей, я хочу, чтобы идентификатор, используемый для сравнения, был значением некоторого ребенка.
"Старый" XML выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Documents>
<Document id="001">
<Tags>
<Tag id="document_id">someIDfilename.pdf</Tag>
<Tag id="document_type">Type A</Tag>
<Tag id="document_text">A very important document of course.</Tag>
<Tags>
</Document>
<Document id="018">
<Tags>
<Tag id="document_id">someOtherIDfilename.pdf</Tag>
<Tag id="document_type">Type B</Tag>
<Tag id="document_text">Another very important document.</Tag>
<Tags>
</Document>
</Documents>
</Root>
Второй Docoument должен быть заменен эквивалентом следующего XML, при этом ID, который я должен использовать, является значением document_id (поскольку "id" узла Document иногда перезаписывается или изменяется):
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Documents>
<Document id="014">
<Tags>
<Tag id="document_id">someOtherIDfilename.pdf</Tag>
<Tag id="document_type">Type B</Tag>
<Tag id="document_text">The oh so important new document text.</Tag>
<Tags>
</Document>
</Documents>
</Root>
Ожидается, что результат будет выглядеть так:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Documents>
<Document id="001">
<Tags>
<Tag id="document_id">someIDfilename.pdf</Tag>
<Tag id="document_type">Type A</Tag>
<Tag id="document_text">A very important document of course.</Tag>
<Tags>
</Document>
<Document id="018">
<Tags>
<Tag id="document_id">someOtherIDfilename.pdf</Tag>
<Tag id="document_type">Type B</Tag>
<Tag id="document_text">The oh so important new document text.</Tag>
<Tags>
</Document>
</Documents>
</Root>
Q1: это возможно с помощью XSLT? Или я должен использовать Java / DOM?
Q2: Если Q1== да: кто-нибудь может решить это здесь?
Лучший! Philipp
1 ответ
Использование процессора XSLT 2.0, такого как Saxon 9:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="doc2-url" select="'test2014032603.xml'"/>
<xsl:variable name="doc2" select="doc($doc2-url)"/>
<xsl:key name="id" match="Document" use="Tags/Tag[@id = 'document_id']"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Document[key('id', Tags/Tag[@id = 'document_id'], $doc2)]">
<xsl:copy>
<xsl:copy-of select="@id, key('id', Tags/Tag[@id = 'document_id'], $doc2)/node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
С XSLT 1.0 это также возможно, но для переключения контекста между документами для использования ключа код оказывается запутанным:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:param name="doc2-url" select="'test2014032603.xml'"/>
<xsl:variable name="doc2" select="document($doc2-url)"/>
<xsl:key name="id" match="Document" use="Tags/Tag[@id = 'document_id']"/>
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Document[Tags/Tag[@id = 'document_id']]">
<xsl:variable name="this" select="."/>
<xsl:for-each select="$doc2">
<xsl:choose>
<xsl:when test="key('id', $this/Tags/Tag[@id = 'document_id'])">
<xsl:for-each select="key('id', $this/Tags/Tag[@id = 'document_id'])">
<xsl:copy>
<xsl:copy-of select="$this/@id"/>
<xsl:copy-of select="node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$this"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>