I have a Subversion changelog in xml format, created with
svn log http://svnurl -r {2014-01-01}:{2014-05-01} --xml > changelog.xml
This gives me an XML file with
<?xml version="1.0" encoding="UTF-8"?>
<log>
<logentry
revision="1234">
<author>foo</author>
<date>2014-02-14T13:19:30.288981Z</date>
<msg>Commit by foo</msg>
</logentry>
<logentry
revision="1235">
<author>bar</author>
<date>2014-02-14T13:57:54.506257Z</date>
<msg>Commit1 by bar</msg>
</logentry>
<logentry
revision="1236">
<author>bar</author>
<date>2014-03-14T13:57:54.506257Z</date>
<msg>Commit2 by bar</msg>
</logentry>
</log>
I would like to transform this to a HTML file:
<html>
<body>
<h2>Change log by author</h2>
<ul>
<li><h3>foo</h3>
<ul>
<li>Commit by foo</li>
</ul>
</li>
<li><h3>bar</h3>
<ul>
<li>Commit1 by bar</li>
<li>Commit2 by bar</li>
</ul>
</li>
</ul>
</body>
</html>
This is what I came up with after a couple of hours of googling and stackoverflowing (no previous xml knowledge):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h2>Change log</h2>
<ul>
<xsl:template match="/">
<xsl:for-each-group select="log/logentry" group-by="author">
<li><h3><xsl:value-of select="author"/></h3>
<ul>
<xsl:for-each select="current-group()">
<li><xsl:value-of select="msg"/></li>
</xsl:for-each>
</ul>
</li>
</xsl:for-each-group>
</xsl:template>
</ul>
</body>
</html>
</xsl:stylesheet>
I tested this with XML Notepad but unfortunately I get no output. Also Internet Explorer and Chrome don’t transform the file. What’s the obvious thing that I’m missing here?
EDIT: I dumped Microsoft XML Notepad and installed a 30 day evaluation version of Altova Missionkit. With that, and while following an example about The Muenchian Method I found on http://www.jenitennison.com/xslt/grouping/muenchian.html, I came up with this:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="changelog-by-author" match="logentry" use="author" />
<xsl:template match="log">
<xsl:for-each select="logentry[count(. | key('changelog-by-author', author)[1]) = 1]">
<xsl:sort select="author" />
<h2><xsl:value-of select="author" /></h2>
<ul>
<xsl:for-each select="key('changelog-by-author', author)">
<xsl:sort select="msg" />
<li><xsl:value-of select="msg" /></li>
</xsl:for-each>
</ul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The resulting HTML is now what I was looking for.
What wasn’t in my original question, but what I would like to add, is the revision number. I’ll add that when I find it.
У меня проблема с синтаксическим анализом xml, фактически с его преобразованием.
Ошибка, которую я получаю:
ERROR: 'Namespace for prefix 'SOAP-ENV' has not been declared.'
Jul 8, 2011 3:24:54 PM kumar.runs.start$2 run
SEVERE: null
javax.xml.transform.TransformerException: java.lang.RuntimeException: Namespace for prefix 'SOAP-ENV' has not been declared.
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:716)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:313).........
Я использую следующий код:
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser parser = saxFactory.newSAXParser();
XMLReader reader = new XMLTrimFilter(parser.getXMLReader());
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "no");
DOMResult result = new DOMResult();
SAXSource ss = new SAXSource(reader, is);
transformer.transform(ss, result);
return (Document)result.getNode();
XMLTrimFilter — это настраиваемая реализация, расширяющая XMLFilterImpl.
Также я наткнулся на это:
Жук
но это довольно старый вопрос. Есть у кого-нибудь идеи, как это исправить?
Благодаря!
[Изменить: XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<swp:addOwnRet xmlns:swbep="urn:SWBEP">
<apples>33</apples>
<bucket>
<orange>5</orange>
<banana>5</banana>
</bucket>
</swp:addOwnRet>
</SOAP-ENV:Body>
]
Редактировать 2:
XMLTrimFilter:
package kumar.srcs;
import java.io.CharArrayWriter; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLFilterImpl;
открытый класс XMLTrimFilter расширяет XMLFilterImpl {
private CharArrayWriter contents = new CharArrayWriter();
public XMLTrimFilter(XMLReader parent){
super(parent);
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException{
writeContents();
super.startElement(uri, localName, qName, atts);
}
public void characters(char ch[], int start, int length){
contents.write(ch, start, length);
}
public void endElement(String uri, String localName, String qName) throws SAXException{
writeContents();
super.endElement(uri, localName, qName);
}
public void ignorableWhitespace(char ch[], int start, int length){}
private void writeContents() throws SAXException{
char ch[] = contents.toCharArray();
if(!isWhiteSpace(ch))
super.characters(ch, 0, ch.length);
contents.reset();
}
private boolean isWhiteSpace(char ch[]){
for(int i = 0; i<ch.length; i++){
if(!Character.isWhitespace(ch[i]))
return false;
}
return true;
}
}
I have an XML string that I have to parse and update (transformer)
String ji = "<book><person><first>p</first><last>m</last><age>22</age></person><person><first>b</first><last>g</last><age>46</age></person><person><first>s</first><last>j</last><age>40</age></person></book>";
ByteArrayInputStream str = new ByteArrayInputStream(ji.getBytes());
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(str);
doc.getDocumentElement().normalize();
str.reset();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
NodeList listOfPersons = doc.getElementsByTagName("person");
int total = listOfPersons.getLength();
for(int i = 0; i < total; i++)
{
Node firstpersonnode = listOfPersons.item(i);
if(firstpersonnode.getNodeType() == Node.ELEMENT_NODE)
{
Element firstPersonElement = (Element)firstpersonnode;
NodeList firstNameList = firstPersonElement.getElementsByTagName("first");
Element firstNameElement = (Element)firstNameList.item(0);
NodeList textFNList = firstNameElement.getChildNodes();
Text t = (Text) textFNList.item(0);
String p = t.toString();
System.out.println("First Name : " +p);
t.setData("sdasdsa");
//String q = t.toString();
//response.write("First Name : " +q);
NodeList lastNameList = firstPersonElement.getElementsByTagName("last");
Element lastNameElement = (Element)lastNameList.item(0);
NodeList textLNList = lastNameElement.getChildNodes();
System.out.println("Last Name : " + ((Node)textLNList.item(0)).getNodeValue().trim());
NodeList ageList = firstPersonElement.getElementsByTagName("age");
Element ageElement = (Element)ageList.item(0);
NodeList textAgeList = ageElement.getChildNodes();
System.out.println("Age : " + ((Node)textAgeList.item(0)).getNodeValue().trim());
}
}
I then write the ByteArrayOutputStream to an OutputStream becoz I need it in that format for the Transformer.
oos = bos;
str.reset();
Source source = new DOMSource(doc);
Result res = new StreamResult(oos);
Transformer x = TransformerFactory.newInstance().newTransformer();
x.transform(source,res);
System.out.println(«now the string is = «+oos.toString());
Which Transforms it:
Now my output is the Old XML string + some xml declaration + the Updated XML string.
First Name : p
Last Name : m
Age : 22
First Name : b
Last Name : g
Age : 46
First Name : s
Last Name : j
Age : 40
now the string is = <book><person><first>p</first><last>m</last><age>22</age></person><person><first>b</first><last>g</last><age>46</age></person><person><first>s</first><last>j</last><age>40</age></person></book><?xml version="1.0" encoding="utf-8"?>
<book><person><first>sdasdsa</first><last>m</last><age>22</age></person><person><first>sdasdsa</first><last>g</last><age>46</age></person><person><first>sdasdsa</first><last>j</last><age>40</age></person></book>
I only need to update the string
