Удаление пустых тегов из XML через XSLT
У меня был xml следующего шаблона
<?xml version="1.0" encoding="UTF-8"?>
<Person>
<FirstName>Ahmed</FirstName>
<MiddleName/>
<LastName>Aboulnaga</LastName>
<CompanyInfo>
<CompanyName>IPN Web</CompanyName>
<Title/>
<Role></Role>
<Department>
</Department>
</CompanyInfo>
</Person>
Я использовал следующий xslt (полученный из форумов) в попытке удалить пустые теги
<xsl:template match="@*|node()">
<xsl:if test=". != '' or ./@* != ''">
<xsl:copy>
<xsl:copy-of select = "@*"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:if>
Используемый xslt успешно удаляет теги, такие как
<Title/>
<Role></Role>
... но не работает, когда пустые теги находятся на двух строках, например:
<Department>
</Department>
Есть ли какое-либо исправление для этого?
Ответы
Ответ 1
Это преобразование вообще не требует каких-либо условных инструкций XSLT и не использует явных приоритетов:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*[not(@*|*|comment()|processing-instruction())
and normalize-space()=''
]"/>
</xsl:stylesheet>
При применении к предоставленному XML-документу:
<Person>
<FirstName>Ahmed</FirstName>
<MiddleName/>
<LastName>Aboulnaga</LastName>
<CompanyInfo>
<CompanyName>IPN Web</CompanyName>
<Title/>
<Role></Role>
<Department>
</Department>
</CompanyInfo>
</Person>
он производит желаемый, правильный результат:
<Person>
<FirstName>Ahmed</FirstName>
<LastName>Aboulnaga</LastName>
<CompanyInfo>
<CompanyName>IPN Web</CompanyName>
</CompanyInfo>
</Person>
Ответ 2
<xsl:template match="@*|node()">
<xsl:if test="normalize-space(.) != '' or ./@* != ''">
<xsl:copy>
<xsl:copy-of select = "@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
Ответ 3
(..) Есть ли какое-либо исправление для этого?
Тег на двух строках не является пустым тегом. Это тег, содержащий пробелы внутри (например, новые строки и, возможно, некоторые символы пробела). Функция XPath 1.0 normalize-space()
позволяет нормализовать содержимое ваших тегов, удалив ненужные новые строки.
После того, как вы применили функцию к содержимому тега, вы можете проверить пустую строку. Хороший способ сделать это - применить функцию XPath 1.0 boolean()
к содержимому тега. Если содержимое представляет собой строку нулевой длины, ее результат будет false.
Наконец, вы можете вставлять все, что немного меняет ваше преобразование личности. Вам не нужны инструкции xsl:if
или любой другой дополнительный шаблон.
Окончательное преобразование будет выглядеть так:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates
select="node()[boolean(normalize-space())]
|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Дополнительная заметка
В настоящее время ваша команда xsl:if
также проверяет наличие пустых атрибутов. Таким образом вы фактически удаляете также теги, не содержащие empy, с пустыми атрибутами. Это не похоже на "Удаление пустых тегов". Поэтому будьте осторожны, или вы сомневаетесь в том, что вам не хватает деталей, или вы используете небезопасный код.
Ответ 4
Ваш вопрос не указан. Что означает пустое? Здесь <outer>
пуст?
<outer><inner/></outer>
В любом случае, здесь один подход, который может соответствовать вашему счету:
<xsl:template match="*[not(.//@*) and not( normalize-space() )]" priority="3"/>
Обратите внимание, что вам может потребоваться настроить приоритет в соответствии с вашими потребностями.
Ответ 5
Из того, что я нашел в сети, это самый правильный ответ:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:if test=".!=''">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Ответ 6
Вы можете использовать следующий xslt для удаления пустых тегов/атрибутов:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()">
<xsl:if test="normalize-space(string(.)) != ''
or count(@*[normalize-space(string(.)) != '']) > 0
or count(descendant::*[normalize-space(string(.)) != '']) > 0
or count(descendant::*/@*[normalize-space(string(.)) != '']) > 0">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="@*">
<xsl:if test="normalize-space(string(.)) != ''">
<xsl:copy>
<xsl:apply-templates select="@*" />
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>