有没有办法修改样式 sheet,以便将带有空标签的 XML 文档转换为 <tag />?
Is there a way to modify the style sheet so that it transforms an XML document with empty tags as <tag />?
我从 codeproject 中提取了一些代码来重新缩进 XML 文档。有谁知道我如何修改样式表,以便 XML 文件的转换将导致空标签显示为 <tag />
而不是 <tag></tag>
?
// http://www.codeproject.com/Articles/43309/How-to-create-a-simple-XML-file-using-MSXML-in-C
MSXML2::IXMLDOMDocumentPtr FormatDOMDocument(MSXML2::IXMLDOMDocumentPtr pDoc)
{
LPCSTR const static szStyleSheet =
R"!(<?xml version="1.0" encoding="utf-8"?>)!"
R"!(<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">)!"
R"!( <xsl:output method="xml" indent="yes"/>)!"
R"!( <xsl:template match="@* | node()">)!"
R"!( <xsl:copy>)!"
R"!( <xsl:apply-templates select="@* | node()"/>)!"
R"!( </xsl:copy>)!"
R"!( </xsl:template>)!"
R"!(</xsl:stylesheet>)!";
MSXML2::IXMLDOMDocumentPtr pXmlStyleSheet;
pXmlStyleSheet.CreateInstance(__uuidof(MSXML2::DOMDocument60));
pXmlStyleSheet->loadXML(szStyleSheet);
MSXML2::IXMLDOMDocumentPtr pXmlFormattedDoc;
pXmlFormattedDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
CComPtr<IDispatch> pDispatch;
HRESULT hr = pXmlFormattedDoc->QueryInterface(IID_IDispatch, (void**)&pDispatch);
if (SUCCEEDED(hr))
{
_variant_t vtOutObject;
vtOutObject.vt = VT_DISPATCH;
vtOutObject.pdispVal = pDispatch;
vtOutObject.pdispVal->AddRef();
hr = pDoc->transformNodeToObject(pXmlStyleSheet, vtOutObject);
}
//By default it is writing the encoding = UTF-16. Let us change the encoding to UTF-8
// <?xml version="1.0" encoding="UTF-8"?>
MSXML2::IXMLDOMNodePtr pXMLFirstChild = pXmlFormattedDoc->GetfirstChild();
// A map of the a attributes (vesrsion, encoding) values (1.0, UTF-8) pair
MSXML2::IXMLDOMNamedNodeMapPtr pXMLAttributeMap = pXMLFirstChild->Getattributes();
MSXML2::IXMLDOMNodePtr pXMLEncodNode = pXMLAttributeMap->getNamedItem(_T("encoding"));
pXMLEncodNode->PutnodeValue(_T("UTF-8")); //encoding = UTF-8
return pXmlFormattedDoc;
}
此样式表导致在可能的情况下写入空标记(使用 MSXML6):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*) and not(normalize-space()) and not(comment()) and not(processing-instruction())]">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="./@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
这是通过避免对没有子元素、文本、注释或处理指令的元素使用 xsl:copy
,并使用 xsl:element
复制元素 "manually" 来实现的。请注意,也使用嵌套的 xsl:copy-of
.
复制属性
例如,这个 XML 文档:
<Document>
<empty> </empty>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3/>
<non-empty-3><empty-4/><empty-with-attribute another-attribute="some more text">
</empty-with-attribute>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>
将使用您的 FormatDOMDocument
函数和更新后的样式表转换为以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<empty/>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3/>
<non-empty-3>
<empty-4/>
<empty-with-attribute another-attribute="some more text"/>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>
要按名称将空标签限制为仅某些元素,您可以调整 match
模式以添加对元素名称的检查:contains('|list|of|element|names|', concat('|',name(),'|'))
。请注意,名称列表用 |
分隔,列表的开头和结尾也有一个 |
,我们也将元素名称与这些分隔符连接起来。这个技巧使我们可以使用contains
(它只匹配任何子串)来实现在列表中搜索的效果。
例如,在我之前的示例中允许 non-empty
、empty-2
、empty-4
和 abc:empty-with-namespace
元素的空标签,更新后的样式表将是:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[contains('|non-empty|empty-2|empty-4|abc:empty-with-namespace|', concat('|',name(),'|')) and not(*) and not(normalize-space()) and not(comment()) and not(processing-instruction())]">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="./@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
并且 FormatDOMDocument
的输出将变为:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<empty></empty>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3></empty-3>
<non-empty-3>
<empty-4/>
<empty-with-attribute another-attribute="some more text"></empty-with-attribute>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>
请注意,虽然我们将 non-empty
指定为该列表中可能的空标记,但它并不是空的,因为它实际上有一个文本节点(这正是我们想要的)。另外,请注意 empty
不在我们的列表中,它带有一个结束标记 <empty></empty>
这也是我们在这种情况下想要的(对于 empty-3
也是如此)。
我从 codeproject 中提取了一些代码来重新缩进 XML 文档。有谁知道我如何修改样式表,以便 XML 文件的转换将导致空标签显示为 <tag />
而不是 <tag></tag>
?
// http://www.codeproject.com/Articles/43309/How-to-create-a-simple-XML-file-using-MSXML-in-C
MSXML2::IXMLDOMDocumentPtr FormatDOMDocument(MSXML2::IXMLDOMDocumentPtr pDoc)
{
LPCSTR const static szStyleSheet =
R"!(<?xml version="1.0" encoding="utf-8"?>)!"
R"!(<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">)!"
R"!( <xsl:output method="xml" indent="yes"/>)!"
R"!( <xsl:template match="@* | node()">)!"
R"!( <xsl:copy>)!"
R"!( <xsl:apply-templates select="@* | node()"/>)!"
R"!( </xsl:copy>)!"
R"!( </xsl:template>)!"
R"!(</xsl:stylesheet>)!";
MSXML2::IXMLDOMDocumentPtr pXmlStyleSheet;
pXmlStyleSheet.CreateInstance(__uuidof(MSXML2::DOMDocument60));
pXmlStyleSheet->loadXML(szStyleSheet);
MSXML2::IXMLDOMDocumentPtr pXmlFormattedDoc;
pXmlFormattedDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
CComPtr<IDispatch> pDispatch;
HRESULT hr = pXmlFormattedDoc->QueryInterface(IID_IDispatch, (void**)&pDispatch);
if (SUCCEEDED(hr))
{
_variant_t vtOutObject;
vtOutObject.vt = VT_DISPATCH;
vtOutObject.pdispVal = pDispatch;
vtOutObject.pdispVal->AddRef();
hr = pDoc->transformNodeToObject(pXmlStyleSheet, vtOutObject);
}
//By default it is writing the encoding = UTF-16. Let us change the encoding to UTF-8
// <?xml version="1.0" encoding="UTF-8"?>
MSXML2::IXMLDOMNodePtr pXMLFirstChild = pXmlFormattedDoc->GetfirstChild();
// A map of the a attributes (vesrsion, encoding) values (1.0, UTF-8) pair
MSXML2::IXMLDOMNamedNodeMapPtr pXMLAttributeMap = pXMLFirstChild->Getattributes();
MSXML2::IXMLDOMNodePtr pXMLEncodNode = pXMLAttributeMap->getNamedItem(_T("encoding"));
pXMLEncodNode->PutnodeValue(_T("UTF-8")); //encoding = UTF-8
return pXmlFormattedDoc;
}
此样式表导致在可能的情况下写入空标记(使用 MSXML6):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(*) and not(normalize-space()) and not(comment()) and not(processing-instruction())]">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="./@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
这是通过避免对没有子元素、文本、注释或处理指令的元素使用 xsl:copy
,并使用 xsl:element
复制元素 "manually" 来实现的。请注意,也使用嵌套的 xsl:copy-of
.
例如,这个 XML 文档:
<Document>
<empty> </empty>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3/>
<non-empty-3><empty-4/><empty-with-attribute another-attribute="some more text">
</empty-with-attribute>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>
将使用您的 FormatDOMDocument
函数和更新后的样式表转换为以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<empty/>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3/>
<non-empty-3>
<empty-4/>
<empty-with-attribute another-attribute="some more text"/>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>
要按名称将空标签限制为仅某些元素,您可以调整 match
模式以添加对元素名称的检查:contains('|list|of|element|names|', concat('|',name(),'|'))
。请注意,名称列表用 |
分隔,列表的开头和结尾也有一个 |
,我们也将元素名称与这些分隔符连接起来。这个技巧使我们可以使用contains
(它只匹配任何子串)来实现在列表中搜索的效果。
例如,在我之前的示例中允许 non-empty
、empty-2
、empty-4
和 abc:empty-with-namespace
元素的空标签,更新后的样式表将是:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[contains('|non-empty|empty-2|empty-4|abc:empty-with-namespace|', concat('|',name(),'|')) and not(*) and not(normalize-space()) and not(comment()) and not(processing-instruction())]">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="./@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
并且 FormatDOMDocument
的输出将变为:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<empty></empty>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3></empty-3>
<non-empty-3>
<empty-4/>
<empty-with-attribute another-attribute="some more text"></empty-with-attribute>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>
请注意,虽然我们将 non-empty
指定为该列表中可能的空标记,但它并不是空的,因为它实际上有一个文本节点(这正是我们想要的)。另外,请注意 empty
不在我们的列表中,它带有一个结束标记 <empty></empty>
这也是我们在这种情况下想要的(对于 empty-3
也是如此)。