Как "выбрать" из XML с пространствами имен?
У меня есть документ XML что-то вроде:
<?xml version="1.0" encoding="utf-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="urn:schemas-microsoft-com:office:spreadsheet">
<Worksheet ss:Name="Worksheet1">
<Table>
<Column ss:Width="100"></Column>
<Row>
<Cell ss:Index="1" ss:StyleID="headerStyle">
<Data ss:Type="String">Submitted By</Data>
</Cell>
</Row>
<Row>
<Cell ss:Index="1" ss:StyleID="alternatingItemStyle">
<Data ss:Type="String">Value1-0</Data>
</Cell>
</Row>
</Table>
<AutoFilter xmlns="urn:schemas-microsoft-com:office:excel"
x:Range="R1C1:R1C5"></AutoFilter>
</Worksheet>
</Workbook>
Проблема заключается в попытке выбрать строки с помощью
<xsl:for-each select="//Row">
<xsl:copy-of select="."/>
</xsl:for-each>
Это не соответствует. Я удалил все интервалы между именами и отлично работает. Итак, как мне получить "select" для соответствия Row?
Ответы
Ответ 1
Объявите префикс пространства имен для пространства имен в XSLT, а затем select
с помощью этого префикса:
<xsl:stylesheet ... xmlns:os="urn:schemas-microsoft-com:office:spreadsheet">
...
<xsl:for-each select="//os:Row">
...
</xsl:for-each>
...
</xsl:stylesheet>
Это обычно приводит к тому, что XPaths легко читаются. Однако инструменты XSLT/XPath генерируют следующий эквивалентный код:
<xsl:for-each select="//*[local-name()='Row' = and namespace-uri()='urn:schemas-microsoft-com:office:spreadsheet']">
...
</xsl:for-each>
Ответ 2
Если вам не интересно пространство имен, вы можете использовать функцию "local-name()" XPath:
<xsl:for-each select="//*[local-name() = 'Row']">
<xsl:copy-of select="."/>
</xsl:for-each>
В качестве альтернативы то же самое можно выразить так. Я не уверен, что это стандартный XPath, и если все реализации XPath поддерживают его (ColdFusion делает, так, вероятно, и Java). Может быть, кто-то знает, соответствует ли это стандарту.
<xsl:for-each select="//:Row">
<xsl:copy-of select="."/>
</xsl:for-each>
Ответ 3
Tomalek и ckarras дают хорошие ответы, но я хочу прояснить причины, лежащие в их основе.
Элементы, которые вы не сопоставляете, находятся в пространстве имен по умолчанию области, в которой они встречаются в документе, то есть они находятся в пространстве имен, объявленном для этой области без префикса (например,
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
в элементе Workbook
). Несмотря на то, что в тэгах отсутствует префикс пространства имен, они находятся в пространстве имен.
Однако XPath требует, чтобы все имена элементов в пространстве имен были квалифицированы с помощью префикса или что пространство имен должно быть явно указано с помощью namespace-uri()
в предикате. Следовательно, вы должны либо использовать функцию local-name()
в предикате для соответствия имени элемента (а также использовать функцию namespace-uri()
, если есть опасность столкновения имен в пространствах имен), или вы должны объявить каждое пространство имен, в котором вы хотите сопоставлять элементы в XPaths с префиксом и квалифицировать имена элементов с их префиксами пространства имен в выражениях XPath.